mirror of https://github.com/IoTcat/LoRa-mqtt.git
pull/1/head
parent
bdebb6bdce
commit
3486ece12f
6 changed files with 686 additions and 0 deletions
@ -0,0 +1 @@ |
|||||||
|
/.vscode/* |
@ -0,0 +1,61 @@ |
|||||||
|
#ifndef __LORA_MATT_H__ |
||||||
|
#define __LORA_MATT_H__ |
||||||
|
|
||||||
|
#define MAX_STRINGVEC_SIZE 20 |
||||||
|
#include "lora-socket.h" |
||||||
|
|
||||||
|
|
||||||
|
class LoRaMQTT{ |
||||||
|
|
||||||
|
public: |
||||||
|
|
||||||
|
inline void ini(){ |
||||||
|
socket.ini(); |
||||||
|
socket.onReceived(_onReceived); |
||||||
|
} |
||||||
|
|
||||||
|
inline void core(){ |
||||||
|
socket.core(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
inline void publish(const String& subject, const String& content){ |
||||||
|
String s = subject + "$" + content; |
||||||
|
socket.udp(s); |
||||||
|
} |
||||||
|
|
||||||
|
inline void subscribe(const String& subject){ |
||||||
|
this->_subjects.PushBack(subject); |
||||||
|
} |
||||||
|
|
||||||
|
inline static void onReceived(void (*f)(String, String)){ |
||||||
|
_f = f; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private: |
||||||
|
static LoRaSocket socket; |
||||||
|
static StringVec _subjects; |
||||||
|
static void (*_f)(String, String); |
||||||
|
|
||||||
|
inline static void _onReceived(String msg, String from, String to, String type){ |
||||||
|
|
||||||
|
String subject = msg.substring(0, msg.indexOf('$')); |
||||||
|
String content = msg.substring(msg.indexOf('$') + 1, msg.length()); |
||||||
|
|
||||||
|
if(_subjects.Find(subject) != -1){ |
||||||
|
_f(subject, content); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
LoRaSocket LoRaMQTT::socket; |
||||||
|
StringVec LoRaMQTT::_subjects; |
||||||
|
void (*LoRaMQTT::_f)(String, String); |
||||||
|
|
||||||
|
|
||||||
|
#endif //__LORA_MATT_H__
|
@ -0,0 +1,32 @@ |
|||||||
|
|
||||||
|
#define LORA_SOCKET_IP "2.2.2.2" |
||||||
|
|
||||||
|
#include "lora-mqtt.h" |
||||||
|
|
||||||
|
|
||||||
|
LoRaMQTT mqtt; |
||||||
|
|
||||||
|
void msg(String subject, String msg){ |
||||||
|
Serial.println(subject); |
||||||
|
Serial.println(msg); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void setup(){ |
||||||
|
Serial.begin(115200); |
||||||
|
if(!LoRa.begin(433E6) ){ |
||||||
|
Serial.println("LoRa Failuer"); |
||||||
|
while(1); |
||||||
|
} |
||||||
|
LoRa.receive(); |
||||||
|
mqtt.ini(); |
||||||
|
mqtt.subscribe("lalala"); |
||||||
|
mqtt.onReceived(msg); |
||||||
|
//mqtt.publish("lalala", "aaaaa");
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void loop(){ |
||||||
|
|
||||||
|
mqtt.core(); |
||||||
|
} |
@ -0,0 +1,246 @@ |
|||||||
|
#ifndef __LORA_SOCKET_H__ |
||||||
|
#define __LORA_SOCKET_H__ |
||||||
|
|
||||||
|
#include <LoRa.h> |
||||||
|
#include "vector.h" |
||||||
|
#include "stringVec.h" |
||||||
|
|
||||||
|
#ifndef LORA_SOCKET_IP |
||||||
|
#define LORA_SOCKET_IP "0.0.0.0" |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef MAX_RECEIVE_STACK_SIZE |
||||||
|
#define MAX_RECEIVE_STACK_SIZE 5 |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef MAX_SEND_STACK_SIZE |
||||||
|
#define MAX_SEND_STACK_SIZE 5 |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef MAX_TCP_TRY_TIMES |
||||||
|
#define MAX_TCP_TRY_TIMES 8 |
||||||
|
#endif |
||||||
|
|
||||||
|
|
||||||
|
class LoRaSocket { |
||||||
|
public: |
||||||
|
LoRaSocket(){} |
||||||
|
static void core(); |
||||||
|
static void ini(); |
||||||
|
static void udp(const String& msg, const String& to = "0.0.0.0"); |
||||||
|
static void tcp(const String& msg, const String& to); |
||||||
|
static void rtcp(const String& msg); |
||||||
|
inline static void onReceived(void (*f)(String, String, String, String)){ |
||||||
|
_f = f; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
private: |
||||||
|
static StringVec tcp_sendingStack, tcp_receiveStack; |
||||||
|
static Vector<unsigned int> tcp_sendingTryTimes; |
||||||
|
static void(*_f)(String, String, String, String); |
||||||
|
inline static void _onReceived(const String& msg, const String& from, const String& to, const String& type){ |
||||||
|
(*_f)(msg, from, to, type); |
||||||
|
}; |
||||||
|
/* LoRa Functions */ |
||||||
|
static void LoRa_tx_mode(); |
||||||
|
static void LoRa_rx_mode(); |
||||||
|
static void send(const String& s); |
||||||
|
static const String receiveMsg(); |
||||||
|
/* Package Functions */ |
||||||
|
inline static const String getIPHeader(const String& to = "0.0.0.0"){ |
||||||
|
return to + "|" + LORA_SOCKET_IP + "|"; |
||||||
|
}; |
||||||
|
inline static bool isGoodPackage(const String& s){ |
||||||
|
String body = s.substring(0, s.length() - 1); |
||||||
|
if(s.substring(s.length() - 1, s.length()) != hash(body)){ |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
}; |
||||||
|
inline static const String getToIP(const String& s){ |
||||||
|
unsigned short left = s.indexOf('|'); |
||||||
|
unsigned short right = s.indexOf('|', left + 1); |
||||||
|
return s.substring(left + 1, right); |
||||||
|
}; |
||||||
|
inline static const String getFromIP(const String& s){ |
||||||
|
unsigned short left = s.indexOf('|', s.indexOf('|') + 1); |
||||||
|
unsigned short right = s.indexOf('|', left + 1); |
||||||
|
return s.substring(left + 1, right); |
||||||
|
}; |
||||||
|
inline static const String getType(const String& s){ |
||||||
|
return s.substring(0, s.indexOf('|')); |
||||||
|
}; |
||||||
|
inline static const String getContent(const String& s){ |
||||||
|
unsigned short left = s.indexOf('|', s.indexOf('|', s.indexOf('|') + 1) + 1); |
||||||
|
unsigned short right = s.indexOf('|', left + 1); |
||||||
|
return decode(s.substring(left + 1, right)); |
||||||
|
}; |
||||||
|
inline static const String getTcpKey(const String& s){ |
||||||
|
int left = s.indexOf('|', s.indexOf('|', s.indexOf('|', s.indexOf('|') + 1) + 1) + 1); |
||||||
|
int right = s.indexOf('|', left + 1); |
||||||
|
return s.substring(left + 1, right); |
||||||
|
}; |
||||||
|
/* receive Functions */ |
||||||
|
static void getMsg(const String& msg); |
||||||
|
/* tcp stack functions */ |
||||||
|
static void checkSendStack(){ |
||||||
|
for(unsigned int i = 0; i < tcp_sendingStack.Size(); i ++){ |
||||||
|
send("tc"+tcp_sendingStack[i]); |
||||||
|
tcp_sendingTryTimes[i] += 1; |
||||||
|
|
||||||
|
if(tcp_sendingTryTimes[i] >= MAX_TCP_TRY_TIMES){ |
||||||
|
tcp_sendingStack.Erase(i); |
||||||
|
tcp_sendingTryTimes.Erase(i); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
inline static void receiveStackClassify(){ |
||||||
|
if(tcp_receiveStack.Size() > MAX_RECEIVE_STACK_SIZE) tcp_receiveStack.Erase(0); |
||||||
|
}; |
||||||
|
inline static void sendStackClassify(){ |
||||||
|
if(tcp_sendingStack.Size() > MAX_SEND_STACK_SIZE) { |
||||||
|
tcp_sendingStack.Erase(0); |
||||||
|
tcp_sendingTryTimes.Erase(0); |
||||||
|
} |
||||||
|
}; |
||||||
|
static void removeByKey(const String& key); |
||||||
|
/* tools */ |
||||||
|
static const String hash(const String& s); |
||||||
|
static const String encode(const String& s){ |
||||||
|
return s; |
||||||
|
}; |
||||||
|
static const String decode(const String& s){ |
||||||
|
return s; |
||||||
|
} |
||||||
|
static const String generateRandomKey(){ |
||||||
|
String o = ""; |
||||||
|
for(unsigned short i = 0; i < 4; i ++){ |
||||||
|
o += char(random(26) + 97); |
||||||
|
} |
||||||
|
return o; |
||||||
|
} |
||||||
|
|
||||||
|
/* timer */ |
||||||
|
static void setInterval(void (*function)(void), const int delay){ |
||||||
|
static unsigned long startTime = millis();
|
||||||
|
|
||||||
|
if(millis() - startTime > delay){ |
||||||
|
(*function)(); |
||||||
|
startTime = millis(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
void LoRaSocket::getMsg(const String& msg){ |
||||||
|
|
||||||
|
if(!isGoodPackage(msg)) return; |
||||||
|
if(getToIP(msg) != LORA_SOCKET_IP && getToIP(msg) != "0.0.0.0") return; |
||||||
|
|
||||||
|
if(getType(msg) == "udp") _onReceived(getContent(msg), getFromIP(msg), getToIP(msg), "udp"); |
||||||
|
if(getType(msg) == "tcp"){ |
||||||
|
rtcp(msg); |
||||||
|
if(tcp_receiveStack.Find(msg) != -1) return; |
||||||
|
_onReceived(getContent(msg), getFromIP(msg), getToIP(msg), "tcp"); |
||||||
|
receiveStackClassify(); |
||||||
|
} |
||||||
|
if(getType(msg) == "rtcp"){ |
||||||
|
removeByKey(getContent(msg)); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void LoRaSocket::udp(const String& msg, const String& to){ |
||||||
|
String fin = "udp|"+ getIPHeader(to) + encode(msg) + "|"; |
||||||
|
fin += hash(fin); |
||||||
|
send(fin); |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
void LoRaSocket::tcp(const String& msg, const String& to){ |
||||||
|
String fin = "tcp|" + getIPHeader(to) + encode(msg) + "|" + generateRandomKey() + "|"; |
||||||
|
fin += hash(fin); |
||||||
|
tcp_sendingStack.PushBack(fin); |
||||||
|
tcp_sendingTryTimes.PushBack(0); |
||||||
|
sendStackClassify(); |
||||||
|
send(fin); |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
void LoRaSocket::rtcp(const String& msg){ |
||||||
|
tcp_receiveStack.PushBack(msg); |
||||||
|
String fin = "rtcp|" + getIPHeader(getFromIP(msg)) + getTcpKey(msg) + "|"; |
||||||
|
fin += hash(fin); |
||||||
|
send(fin); |
||||||
|
} |
||||||
|
|
||||||
|
StringVec LoRaSocket::tcp_sendingStack, LoRaSocket::tcp_receiveStack; |
||||||
|
Vector<unsigned int> LoRaSocket::tcp_sendingTryTimes; |
||||||
|
void (*LoRaSocket::_f)(String, String, String, String); |
||||||
|
|
||||||
|
void LoRaSocket::ini() { |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void LoRaSocket::core() { |
||||||
|
|
||||||
|
/* Listen Msg */ |
||||||
|
if(LoRa.parsePacket()){ |
||||||
|
getMsg(receiveMsg()); |
||||||
|
} |
||||||
|
|
||||||
|
/* check tcp stack */ |
||||||
|
setInterval(checkSendStack, 1000); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void LoRaSocket::LoRa_tx_mode(){ |
||||||
|
LoRa.idle(); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaSocket::LoRa_rx_mode(){ |
||||||
|
LoRa.receive(); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaSocket::send(const String& s){ |
||||||
|
LoRa_tx_mode(); |
||||||
|
delay(200); |
||||||
|
LoRa.beginPacket(); |
||||||
|
LoRa.print(s); |
||||||
|
LoRa.endPacket(); |
||||||
|
delay(200); |
||||||
|
LoRa_rx_mode(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const String LoRaSocket::receiveMsg(){ |
||||||
|
String s = ""; |
||||||
|
while (LoRa.available()) { |
||||||
|
s += (char)LoRa.read(); |
||||||
|
} |
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
const String LoRaSocket::hash(const String& s){ |
||||||
|
unsigned char hashVal = 'k'; |
||||||
|
for(unsigned short i = 0; i < s.length(); i ++){ |
||||||
|
hashVal ^= s.charAt(i); |
||||||
|
} |
||||||
|
hashVal = hashVal % 26 + 97; |
||||||
|
return String((char)hashVal); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void LoRaSocket::removeByKey(const String& key){ |
||||||
|
for(unsigned int i = 0; i < tcp_sendingStack.Size(); i++){ |
||||||
|
if(getTcpKey(tcp_sendingStack[i]) == key) { |
||||||
|
tcp_sendingStack.Erase(i); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endif //__LORA_SOCKET_H__
|
@ -0,0 +1,77 @@ |
|||||||
|
#ifndef __STRINGVEC__ |
||||||
|
#define __STRINGVEC__ |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MAX_STRINGVEC_SIZE |
||||||
|
#define MAX_STRINGVEC_SIZE 10 |
||||||
|
#endif |
||||||
|
|
||||||
|
class StringVec{ |
||||||
|
public:
|
||||||
|
StringVec():_size(0){ |
||||||
|
this->clear(); |
||||||
|
}; |
||||||
|
|
||||||
|
inline void PushBack(const String& ss){ |
||||||
|
if(this->Size() == MAX_STRINGVEC_SIZE){ |
||||||
|
this->shift(); |
||||||
|
} |
||||||
|
this->_s[this->Size()] = ss; |
||||||
|
this->_size ++; |
||||||
|
} |
||||||
|
|
||||||
|
const int Find(const String& ss){ |
||||||
|
for(unsigned i = 0; i < this->Size(); i ++){ |
||||||
|
if(this->_s[i] == ss){ |
||||||
|
return i; |
||||||
|
} |
||||||
|
} |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
void Erase(const int& pos){ |
||||||
|
if(pos < 0 || pos >= this->Size()) return; |
||||||
|
for(unsigned int i = pos+1; i < this->Size(); i ++){ |
||||||
|
this->_s[i-1] = this->_s[i]; |
||||||
|
} |
||||||
|
this->_size --; |
||||||
|
} |
||||||
|
|
||||||
|
const String shift(){ |
||||||
|
String s = this->_s[0]; |
||||||
|
if(this->Size() != 0){ |
||||||
|
for(unsigned int i = 1; i < this->Size(); i ++){ |
||||||
|
this->_s[i-1] = this->_s[i]; |
||||||
|
} |
||||||
|
this->_size --; |
||||||
|
} |
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
void clear(){ |
||||||
|
for(unsigned int i = 0; i < this->Size(); i ++){ |
||||||
|
this->_s[i] = ""; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
inline const int Size(){ |
||||||
|
return this->_size; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
String& operator[](int i){ |
||||||
|
if(i < 0 || i >= this->Size()) return this->_s[0]; |
||||||
|
return this->_s[i]; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
String _s[MAX_STRINGVEC_SIZE]; |
||||||
|
int _size; |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //__STRINGVEC__
|
@ -0,0 +1,269 @@ |
|||||||
|
/*
|
||||||
|
* Vector.h |
||||||
|
* |
||||||
|
* Created on: 05/04/2012 |
||||||
|
* Author: tom |
||||||
|
* Purpose: To play the part of a mutable array in the absence of the STL. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef VECTOR_H |
||||||
|
#define VECTOR_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#ifndef MIN |
||||||
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef MAX |
||||||
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) |
||||||
|
#endif |
||||||
|
|
||||||
|
#define SWAP(type, a, b) type tmp ## a = a; a = b; b = tmp ## a; |
||||||
|
|
||||||
|
template <class ParameterType> class Predicate |
||||||
|
{ |
||||||
|
public: |
||||||
|
virtual void operator() (ParameterType ¶m) = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
template <class VectorType> class Vector |
||||||
|
{ |
||||||
|
// The address of the first element of the vector
|
||||||
|
VectorType *begin; |
||||||
|
// The address one after the last allocated entry in the underlying array
|
||||||
|
VectorType *storage; |
||||||
|
// The index of the most recent element put in the underlying array - the head
|
||||||
|
int head; |
||||||
|
|
||||||
|
public: |
||||||
|
// The value that is returned when the caller asks for an element that is out of the bounds of the vector
|
||||||
|
VectorType OB; |
||||||
|
|
||||||
|
// We can save a few re-sizings if we know how large the array is likely to grow to be
|
||||||
|
Vector(int initialSize = 0) |
||||||
|
{ |
||||||
|
begin = new VectorType[initialSize]; //points to the beginning of the new array
|
||||||
|
head = initialSize - 1; |
||||||
|
storage = begin + initialSize; //points to the element one outside of the array (such that end - begin = capacity)
|
||||||
|
} |
||||||
|
|
||||||
|
Vector(Vector &obj) |
||||||
|
{ |
||||||
|
begin = new VectorType[0]; // Points to the beginning of the new array, it's zero but this line keeps malloc from seg faulting should we delete begin before resizing it
|
||||||
|
head = -1; |
||||||
|
storage = begin; //points to the element one outside of the array (such that end - begin = capacity)
|
||||||
|
|
||||||
|
*this = obj; |
||||||
|
} |
||||||
|
|
||||||
|
// If there's anything in the vector then delete the array, if there's no array then doing will will cause seg faults
|
||||||
|
virtual ~Vector() { delete[] begin; } |
||||||
|
|
||||||
|
Vector &operator=(Vector &obj) |
||||||
|
{ |
||||||
|
// Reallocate the underlying buffer to the same size as the
|
||||||
|
Resize(obj.Size()); |
||||||
|
|
||||||
|
for(int i = 0; i < obj.Size(); i++) |
||||||
|
(*this)[i] = obj[i]; |
||||||
|
|
||||||
|
head = obj.head; |
||||||
|
|
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
void ForEach(Predicate<VectorType> &functor) |
||||||
|
{ |
||||||
|
for(int i = 0; i < Size(); i++) |
||||||
|
functor(begin[i]); |
||||||
|
} |
||||||
|
|
||||||
|
// Swaps the underlying array and characteristics of this vector with another of the same type, very quickly
|
||||||
|
void Swap(Vector &obj) |
||||||
|
{ |
||||||
|
SWAP(int, head, obj.head); |
||||||
|
SWAP(VectorType*, begin, obj.begin); |
||||||
|
SWAP(VectorType*, storage, obj.storage); |
||||||
|
} |
||||||
|
|
||||||
|
// Checks the entire Vector to see whether a matching item exists. Bear in mind that the VectorType might need to implement
|
||||||
|
// equality operator (operator==) for this to work properly.
|
||||||
|
bool Contains(VectorType element) |
||||||
|
{ |
||||||
|
for(int i = 0; i < Size(); i++) |
||||||
|
if(operator [](i) == element) |
||||||
|
return true; |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
int Find(VectorType element) |
||||||
|
{ |
||||||
|
for(int i = 0; i < Size(); i++) |
||||||
|
if(operator [](i) == element) |
||||||
|
return i; |
||||||
|
|
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
void PushBack(VectorType element) { PushBack(&element, 1); } |
||||||
|
|
||||||
|
void PushBack(const VectorType *elements, int len) |
||||||
|
{ |
||||||
|
// If the length plus this's size is greater than the capacity, reallocate to that size.
|
||||||
|
if(len + Size() > Capacity()) |
||||||
|
ReAllocate(MAX(Size() + len, Size() * 2)); |
||||||
|
|
||||||
|
int append = MIN(storage - begin - head - 1, len), prepend = len - append; |
||||||
|
|
||||||
|
// memcpy the data starting at the head all the way up to the last element *(storage - 1)
|
||||||
|
memcpy((begin + head + 1), elements, sizeof(VectorType) * append); |
||||||
|
|
||||||
|
// If there's still data to copy memcpy whatever remains, starting at the first element *(begin) until the end of data. The first step will have ensured
|
||||||
|
// that we don't crash into the tail during this process.
|
||||||
|
memcpy(begin,(elements + append), sizeof(VectorType) * prepend); |
||||||
|
|
||||||
|
// Re-recalculate head and size.
|
||||||
|
head += len; |
||||||
|
} |
||||||
|
|
||||||
|
void Erase(unsigned int position) { Erase(position, position + 1); } |
||||||
|
|
||||||
|
// Erase an arbitrary section of the vector from first up to last minus one. Like the stl counterpart, this is pretty labour intensive so go easy on it.
|
||||||
|
void Erase(int first, int last) |
||||||
|
{ |
||||||
|
// For this we'll set the value of the array at first to the value of the array at last plus one. We'll do that all the way up to toIndex
|
||||||
|
for(int i = 0; i < (Size() - first); i++) |
||||||
|
{ |
||||||
|
// If by trying to fill in the next element with the ones ahead of it we'll be running off the end of the vector, stop.
|
||||||
|
if((i + last) > (Size() - 1)) |
||||||
|
break; |
||||||
|
|
||||||
|
begin[first + i] = begin[last + i]; |
||||||
|
} |
||||||
|
|
||||||
|
// Adjust the head to reflect the new size
|
||||||
|
head -= last - first; |
||||||
|
} |
||||||
|
|
||||||
|
// Remove the most recent element in the array
|
||||||
|
void PopBack() |
||||||
|
{ |
||||||
|
if(Size() > 0) |
||||||
|
head--; |
||||||
|
} |
||||||
|
|
||||||
|
// Empty the vector, or to be precise - forget the fact that there was ever anything in there.
|
||||||
|
void Clear() { head = -1; } |
||||||
|
|
||||||
|
// Returns a bool indicating whether or not there are any elements in the array
|
||||||
|
bool Empty() { return head == -1; } |
||||||
|
|
||||||
|
// Returns the oldest element in the array (the one added before any other)
|
||||||
|
VectorType const &Back() { return *begin; } |
||||||
|
|
||||||
|
// Returns the newest element in the array (the one added after every other)
|
||||||
|
VectorType const &Front() { return begin[head]; } |
||||||
|
|
||||||
|
// Returns the nth element in the vector
|
||||||
|
VectorType &operator[](int n) |
||||||
|
{ |
||||||
|
if(n < Size()) |
||||||
|
return begin[n]; |
||||||
|
else |
||||||
|
return OB; |
||||||
|
} |
||||||
|
|
||||||
|
// Returns a pointer such that the vector's data is laid out between ret to ret + size
|
||||||
|
VectorType *Data() { return begin; } |
||||||
|
|
||||||
|
// Recreates the vector to hold len elements, all being copies of val
|
||||||
|
void Assign(int len, const VectorType &val) |
||||||
|
{ |
||||||
|
delete[] begin; |
||||||
|
|
||||||
|
// Allocate an array the same size as the one passed in
|
||||||
|
begin = new VectorType[len]; |
||||||
|
storage = begin + len; |
||||||
|
|
||||||
|
// Refresh the head and tail, assuming the array is in order, which it really has to be
|
||||||
|
head = len - 1; |
||||||
|
|
||||||
|
for(int i = 0 ; i < Size(); i++) |
||||||
|
begin[i] = val; |
||||||
|
} |
||||||
|
|
||||||
|
// Recreates the vector using an external array
|
||||||
|
void Assign(VectorType *array, int len) |
||||||
|
{ |
||||||
|
delete[] begin; |
||||||
|
|
||||||
|
// Allocate an array the same size as the one passed in
|
||||||
|
begin = new VectorType[len]; |
||||||
|
storage = begin + len; |
||||||
|
|
||||||
|
// Refresh the head and tail, assuming the array is in order, which it really has to be
|
||||||
|
head = len - 1; |
||||||
|
|
||||||
|
// Copy over the memory
|
||||||
|
memcpy(begin, array, sizeof(VectorType) * len); |
||||||
|
} |
||||||
|
|
||||||
|
// Returns the number of elements that the vector will support before needing resizing
|
||||||
|
int Capacity() { return (storage - begin); } |
||||||
|
|
||||||
|
// Returns the number of elements in vector
|
||||||
|
int Size() { return head + 1; } |
||||||
|
|
||||||
|
// Requests that the capacity of the allocated storage space for the elements
|
||||||
|
// of the vector be at least enough to hold size elements.
|
||||||
|
void Reserve(unsigned int size) |
||||||
|
{ |
||||||
|
if(size > Capacity()) |
||||||
|
ReAllocate(size); |
||||||
|
} |
||||||
|
|
||||||
|
// Resizes the vector
|
||||||
|
void Resize(unsigned int size) |
||||||
|
{ |
||||||
|
// If necessary, resize the underlying array to fit the new size
|
||||||
|
if(size > Capacity()) |
||||||
|
ReAllocate(size); |
||||||
|
|
||||||
|
// Now revise the head and size (tail needn't change) to reflect the new size
|
||||||
|
head = size - 1; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
|
||||||
|
void ReAllocate(unsigned int size) |
||||||
|
{ |
||||||
|
// Just in case we're re-allocating less room than we had before, make sure that we don't overrun the buffer by trying to write more elements than
|
||||||
|
// are now possible for this vector to hold.
|
||||||
|
if(Size() > (int)size) |
||||||
|
head = size - 1; |
||||||
|
|
||||||
|
// Allocate an array twice the size of that of the old
|
||||||
|
VectorType *_begin = new VectorType[size]; |
||||||
|
VectorType *_storage = _begin + size; |
||||||
|
|
||||||
|
int _head = Size() - 1; |
||||||
|
|
||||||
|
// Copy across all the old array's data and rearrange it!
|
||||||
|
for(int i = 0; i < Size(); i++) |
||||||
|
_begin[i] = (*this)[i]; |
||||||
|
|
||||||
|
// Free the old memory
|
||||||
|
delete[] begin; |
||||||
|
|
||||||
|
// Redirect the old array to point to the new one
|
||||||
|
begin = _begin; |
||||||
|
storage = _storage; |
||||||
|
head = _head; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // VECTOR_H
|
Loading…
Reference in new issue