Use own memory optimized pointer array implementation
This commit is contained in:
parent
bcef37d9c3
commit
157c9b5ece
|
|
@ -85,3 +85,205 @@ public:
|
|||
protected:
|
||||
void handlePage(const char* buffer, int length) override;
|
||||
};
|
||||
|
||||
template <typename T> class DynamicPointerArray {
|
||||
private:
|
||||
union element
|
||||
{
|
||||
T* singleElement;
|
||||
T** multipleElements;
|
||||
} u;
|
||||
uint16_t arraySize = 0;
|
||||
public:
|
||||
~DynamicPointerArray()
|
||||
{
|
||||
if (arraySize > 2)
|
||||
free(u.multipleElements);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (arraySize > 2)
|
||||
free(u.multipleElements);
|
||||
arraySize = 0;
|
||||
u.singleElement = nullptr;
|
||||
}
|
||||
|
||||
uint16_t size() const { return arraySize; }
|
||||
|
||||
void push_back(T* element){
|
||||
uint16_t currentSize = arraySize;
|
||||
arraySize++;
|
||||
if (currentSize == 0)
|
||||
{
|
||||
u.singleElement = element;
|
||||
}
|
||||
else if (currentSize == 1)
|
||||
{
|
||||
T** newBuffer = (T**) malloc(arraySize * sizeof(T*));
|
||||
if (newBuffer == NULL)
|
||||
throw "Fatal error, no more memory";
|
||||
newBuffer[0] = u.singleElement;
|
||||
newBuffer[1] = element;
|
||||
u.multipleElements = newBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
T** newBuffer = (T**) realloc(u.multipleElements, arraySize * sizeof(T*));
|
||||
if (newBuffer == NULL)
|
||||
throw "Fatal error, no more memory";
|
||||
newBuffer[arraySize - 1] = element;
|
||||
u.multipleElements = newBuffer;
|
||||
}
|
||||
}
|
||||
T* front() const
|
||||
{
|
||||
return get(0);
|
||||
}
|
||||
T* back() const
|
||||
{
|
||||
return get(arraySize - 1);
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return arraySize == 0;
|
||||
}
|
||||
T* operator[](uint16_t index) const
|
||||
{
|
||||
return get(index);
|
||||
}
|
||||
|
||||
T* get(uint16_t index) const
|
||||
{
|
||||
if (index >= arraySize)
|
||||
{
|
||||
throw "Fatal error. Index does not exist.";
|
||||
}
|
||||
if (arraySize == 1)
|
||||
return u.singleElement;
|
||||
else
|
||||
return u.multipleElements[index];
|
||||
}
|
||||
|
||||
|
||||
void remove(uint16_t index)
|
||||
{
|
||||
if (index >= arraySize)
|
||||
{
|
||||
throw "Fatal error. Index does not exist.";
|
||||
}
|
||||
uint16_t currentSize = arraySize;
|
||||
if (currentSize == 1)
|
||||
{
|
||||
u.singleElement = nullptr;
|
||||
}
|
||||
else if (currentSize == 2)
|
||||
{
|
||||
|
||||
if (index == 1)
|
||||
{
|
||||
T* firstElement = u.multipleElements[0];
|
||||
free(u.multipleElements);
|
||||
u.singleElement = firstElement;
|
||||
}
|
||||
else
|
||||
{
|
||||
T* secondElement = u.multipleElements[1];
|
||||
free(u.multipleElements);
|
||||
u.singleElement = secondElement;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = index; i < currentSize - 1; i++)
|
||||
{
|
||||
u.multipleElements[i] = u.multipleElements[i + 1];
|
||||
}
|
||||
T** newBuffer = (T**) realloc(u.multipleElements, arraySize * sizeof(T*));
|
||||
if (newBuffer == NULL)
|
||||
throw "Fatal error, no more memory";
|
||||
u.multipleElements = newBuffer;
|
||||
}
|
||||
arraySize--;
|
||||
|
||||
}
|
||||
|
||||
class DynamicPointerArrayIterator
|
||||
{
|
||||
const DynamicPointerArray* data;
|
||||
uint32_t currentIndex;
|
||||
friend class DynamicPointerArray;
|
||||
public:
|
||||
DynamicPointerArrayIterator(const DynamicPointerArrayIterator& r) :
|
||||
data(r.data),currentIndex(r.currentIndex) { }
|
||||
|
||||
DynamicPointerArrayIterator(const DynamicPointerArray* arr, uint32_t startIndex): data(arr),currentIndex(startIndex) { }
|
||||
T* operator*() const
|
||||
{
|
||||
return data->get(currentIndex);
|
||||
}
|
||||
const DynamicPointerArrayIterator operator++(int)
|
||||
{
|
||||
DynamicPointerArrayIterator temp = *this;
|
||||
++*this;
|
||||
return temp;
|
||||
}
|
||||
DynamicPointerArrayIterator& operator++()
|
||||
{
|
||||
++currentIndex;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const DynamicPointerArrayIterator& lhs)
|
||||
{
|
||||
return currentIndex==lhs.currentIndex;
|
||||
}
|
||||
bool operator!=(const DynamicPointerArrayIterator& lhs)
|
||||
{
|
||||
return currentIndex!=lhs.currentIndex;
|
||||
}
|
||||
};
|
||||
DynamicPointerArrayIterator begin() const{ return DynamicPointerArrayIterator(this,0); }
|
||||
DynamicPointerArrayIterator end() const{ return DynamicPointerArrayIterator(this, arraySize); }
|
||||
|
||||
class DynamicPointerArrayReverseIterator
|
||||
{
|
||||
const DynamicPointerArray* data;
|
||||
uint32_t currentIndex;
|
||||
friend class DynamicPointerArray;
|
||||
public:
|
||||
DynamicPointerArrayReverseIterator(const DynamicPointerArrayReverseIterator& r) :
|
||||
data(r.data),currentIndex(r.currentIndex) { }
|
||||
|
||||
DynamicPointerArrayReverseIterator(const DynamicPointerArray* arr, uint32_t startIndex): data(arr),currentIndex(startIndex) { }
|
||||
T* operator*() const
|
||||
{
|
||||
return data->get(currentIndex);
|
||||
}
|
||||
const DynamicPointerArrayReverseIterator operator++(int)
|
||||
{
|
||||
DynamicPointerArrayReverseIterator temp = *this;
|
||||
++*this;
|
||||
return temp;
|
||||
}
|
||||
DynamicPointerArrayReverseIterator& operator++()
|
||||
{
|
||||
currentIndex--;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const DynamicPointerArrayReverseIterator& lhs)
|
||||
{
|
||||
return currentIndex==lhs.currentIndex;
|
||||
}
|
||||
bool operator!=(const DynamicPointerArrayReverseIterator& lhs)
|
||||
{
|
||||
return currentIndex!=lhs.currentIndex;
|
||||
}
|
||||
};
|
||||
DynamicPointerArrayReverseIterator rbegin() const{ return DynamicPointerArrayReverseIterator(this,arraySize - 1); }
|
||||
DynamicPointerArrayReverseIterator rend() const{ return DynamicPointerArrayReverseIterator(this, 0 - 1); }
|
||||
|
||||
void erase(DynamicPointerArrayIterator iterator)
|
||||
{
|
||||
remove(iterator.currentIndex);
|
||||
}
|
||||
};
|
||||
|
|
@ -924,8 +924,20 @@ void Span::processSerialCommand(const char *c){
|
|||
if(invalidUUID((*chr)->type,(*chr)->isCustom))
|
||||
LOG0(" *** ERROR #%d! Format of UUID is invalid ***\n",++nErrors);
|
||||
else
|
||||
if(std::find_if((*svc)->Characteristics.begin(),chr,[chr](SpanCharacteristic *c)->boolean{return(c->hapChar==(*chr)->hapChar);})!=chr)
|
||||
// if(std::find_if((*svc)->Characteristics.begin(),chr,[chr](SpanCharacteristic *c)->boolean{return(c->hapChar==(*chr)->hapChar);})!=chr)
|
||||
{
|
||||
bool hasHabChar = false;
|
||||
for(auto chara=(*svc)->Characteristics.begin(); chara!=(*svc)->Characteristics.end(); chara++)
|
||||
{
|
||||
if ((*chara)->hapChar == (*chr)->hapChar && chara != chr)
|
||||
{
|
||||
hasHabChar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasHabChar)
|
||||
LOG0(" *** ERROR #%d! Characteristic already defined for this Service ***\n",++nErrors);
|
||||
}
|
||||
|
||||
if((*chr)->setRangeError)
|
||||
LOG0(" *** WARNING #%d! Attempt to set Custom Range for this Characteristic ignored ***\n",++nWarnings);
|
||||
|
|
@ -938,8 +950,19 @@ void Span::processSerialCommand(const char *c){
|
|||
|
||||
} // Characteristics
|
||||
|
||||
for(auto req=(*svc)->req.begin(); req!=(*svc)->req.end(); req++){
|
||||
if(std::find_if((*svc)->Characteristics.begin(),(*svc)->Characteristics.end(),[req](SpanCharacteristic *c)->boolean{return(c->hapChar==*req);})==(*svc)->Characteristics.end())
|
||||
for(auto req=(*svc)->req.begin(); req!=(*svc)->req.end(); req++)
|
||||
// if(std::find_if((*svc)->Characteristics.begin(),(*svc)->Characteristics.end(),[req](SpanCharacteristic *c)->boolean{return(c->hapChar==*req);})==(*svc)->Characteristics.end())
|
||||
{
|
||||
bool hasHabChar = false;
|
||||
for(auto chara=(*svc)->Characteristics.begin(); chara!=(*svc)->Characteristics.end(); chara++)
|
||||
{
|
||||
if ((*chara)->hapChar == *req)
|
||||
{
|
||||
hasHabChar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasHabChar)
|
||||
LOG0(" *** WARNING #%d! Required '%s' Characteristic for this Service not found ***\n",++nWarnings,(*req)->hapName);
|
||||
}
|
||||
|
||||
|
|
@ -1645,7 +1668,6 @@ boolean Span::updateDatabase(boolean updateMDNS){
|
|||
for(auto svc=(*acc)->Services.begin(); svc!=(*acc)->Services.end(); svc++){
|
||||
if((void(*)())((*svc)->*(&SpanService::loop)) != (void(*)())(&SpanService::loop)) { // save pointers to services in Loops vector
|
||||
homeSpan.Loops.push_back((*svc));
|
||||
std::vector<SpanService*>(homeSpan.Loops).swap(homeSpan.Loops); // shrink vector to fit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1729,7 +1751,6 @@ SpanService::SpanService(const char *type, const char *hapName, boolean isCustom
|
|||
this->isCustom=isCustom;
|
||||
|
||||
homeSpan.Accessories.back()->Services.push_back(this);
|
||||
std::vector<SpanService*>(homeSpan.Accessories.back()->Services).swap(homeSpan.Accessories.back()->Services); // shrink vector to fit
|
||||
accessory=homeSpan.Accessories.back();
|
||||
iid=++(homeSpan.Accessories.back()->iidCount);
|
||||
}
|
||||
|
|
@ -1784,7 +1805,6 @@ SpanService *SpanService::setHidden(){
|
|||
|
||||
SpanService *SpanService::addLink(SpanService *svc){
|
||||
linkedServices.push_back(svc);
|
||||
std::vector<SpanService*>(linkedServices).swap(linkedServices); // shrink vector to fit
|
||||
return(this);
|
||||
}
|
||||
|
||||
|
|
@ -1845,7 +1865,6 @@ SpanCharacteristic::SpanCharacteristic(HapChar *hapChar, boolean isCustom){
|
|||
}
|
||||
|
||||
homeSpan.Accessories.back()->Services.back()->Characteristics.push_back(this);
|
||||
std::vector<SpanCharacteristic*>(homeSpan.Accessories.back()->Services.back()->Characteristics).swap(homeSpan.Accessories.back()->Services.back()->Characteristics); // shrink vector to fit
|
||||
|
||||
iid=++(homeSpan.Accessories.back()->iidCount);
|
||||
service=homeSpan.Accessories.back()->Services.back();
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
#include "HAPConstants.h"
|
||||
#include "HapQR.h"
|
||||
#include "Characteristics.h"
|
||||
#include "CallContext.h"
|
||||
|
||||
using std::vector;
|
||||
using std::unordered_map;
|
||||
|
|
@ -247,13 +248,13 @@ class Span{
|
|||
PushButton *controlButton = NULL; // controls HomeSpan configuration and resets
|
||||
Network network; // configures WiFi and Setup Code via either serial monitor or temporary Access Point
|
||||
SpanWebLog webLog; // optional web status/log
|
||||
TaskHandle_t pollTaskHandle = NULL; // optional task handle to use for poll() function
|
||||
TaskHandle_t pollTaskHandle = pollTaskHandle; // optional task handle to use for poll() function
|
||||
boolean verboseWifiReconnect = true; // set to false to not print WiFi reconnect attempts messages
|
||||
|
||||
SpanOTA spanOTA; // manages OTA process
|
||||
SpanConfig hapConfig; // track configuration changes to the HAP Accessory database; used to increment the configuration number (c#) when changes found
|
||||
vector<SpanAccessory *> Accessories; // vector of pointers to all Accessories
|
||||
vector<SpanService *> Loops; // vector of pointer to all Services that have over-ridden loop() methods
|
||||
DynamicPointerArray<SpanAccessory> Accessories; // vector of pointers to all Accessories
|
||||
DynamicPointerArray<SpanService> Loops; // vector of pointer to all Services that have over-ridden loop() methods
|
||||
vector<SpanBuf> Notifications; // vector of SpanBuf objects that store info for Characteristics that are updated with setVal() and require a Notification Event
|
||||
vector<SpanButton *> PushButtons; // vector of pointer to all PushButtons
|
||||
unordered_map<uint64_t, uint32_t> TimedWrites; // map of timed-write PIDs and Alarm Times (based on TTLs)
|
||||
|
|
@ -360,7 +361,7 @@ class Span{
|
|||
Span& setRebootCallback(void (*f)(uint8_t),uint32_t t=DEFAULT_REBOOT_CALLBACK_TIME){rebootCallback=f;rebootCallbackTime=t;return(*this);}
|
||||
|
||||
uint32_t getAutoPollMinFreeStack(){
|
||||
return uxTaskGetStackHighWaterMark(pollTaskHandle);
|
||||
return pollTaskHandle != NULL ? uxTaskGetStackHighWaterMark(pollTaskHandle) : 0;
|
||||
}
|
||||
|
||||
void autoPoll(uint32_t stackSize=8192, uint32_t priority=1, uint32_t cpu=0){ // start pollTask()
|
||||
|
|
@ -392,7 +393,7 @@ class SpanAccessory{
|
|||
|
||||
uint32_t aid=0; // Accessory Instance ID (HAP Table 6-1)
|
||||
int iidCount=0; // running count of iid to use for Services and Characteristics associated with this Accessory
|
||||
vector<SpanService *> Services; // vector of pointers to all Services in this Accessory
|
||||
DynamicPointerArray<SpanService> Services; // vector of pointers to all Services in this Accessory
|
||||
|
||||
int sprintfAttributes(char *cBuf, int flags); // prints Accessory JSON database into buf, unless buf=NULL; return number of characters printed, excluding null terminator, even if buf=NULL
|
||||
|
||||
|
|
@ -419,8 +420,8 @@ class SpanService{
|
|||
const char *hapName; // HAP Name
|
||||
boolean hidden=false; // optional property indicating service is hidden
|
||||
boolean primary=false; // optional property indicating service is primary
|
||||
vector<SpanCharacteristic *> Characteristics; // vector of pointers to all Characteristics in this Service
|
||||
vector<SpanService *> linkedServices; // vector of pointers to any optional linked Services
|
||||
DynamicPointerArray<SpanCharacteristic> Characteristics; // vector of pointers to all Characteristics in this Service
|
||||
DynamicPointerArray<SpanService> linkedServices; // vector of pointers to any optional linked Services
|
||||
boolean isCustom; // flag to indicate this is a Custom Service
|
||||
SpanAccessory *accessory=NULL; // pointer to Accessory containing this Service
|
||||
|
||||
|
|
@ -438,7 +439,7 @@ class SpanService{
|
|||
SpanService *setPrimary(); // sets the Service Type to be primary and returns pointer to self
|
||||
SpanService *setHidden(); // sets the Service Type to be hidden and returns pointer to self
|
||||
SpanService *addLink(SpanService *svc); // adds svc as a Linked Service and returns pointer to self
|
||||
vector<SpanService *> getLinks(){return(linkedServices);} // returns linkedServices vector for use as range in "for-each" loops
|
||||
DynamicPointerArray<SpanService>& getLinks(){return(linkedServices);} // returns linkedServices vector for use as range in "for-each" loops
|
||||
|
||||
virtual boolean update() {return(true);} // placeholder for code that is called when a Service is updated via a Controller. Must return true/false depending on success of update
|
||||
virtual void loop(){} // loops for each Service - called every cycle if over-ridden with user-defined code
|
||||
|
|
|
|||
Loading…
Reference in New Issue