String indexer std::string removed
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
#include "StringIndexer.h"
|
#include "StringIndexer.h"
|
||||||
|
|
||||||
std::map<StringIndexer::index_t, StringIndexer::StringCounter> StringIndexer::strings;
|
StringIndexer::Strings StringIndexer::strings;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
// vim: ts=2 sw=2 expandtab
|
// vim: ts=2 sw=2 expandtab
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <assert.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "TinyString.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -10,9 +13,11 @@
|
|||||||
*/
|
*/
|
||||||
class StringIndexer
|
class StringIndexer
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
class StringCounter
|
class StringCounter
|
||||||
{
|
{
|
||||||
std::string str;
|
TinyString str;
|
||||||
uint8_t used=0;
|
uint8_t used=0;
|
||||||
friend class StringIndexer;
|
friend class StringIndexer;
|
||||||
|
|
||||||
@@ -29,13 +34,13 @@ class StringIndexer
|
|||||||
public:
|
public:
|
||||||
using index_t = uint8_t;
|
using index_t = uint8_t;
|
||||||
|
|
||||||
static const std::string& str(const index_t& index)
|
static const TinyString& str(const index_t& index)
|
||||||
{
|
{
|
||||||
static std::string dummy;
|
static TinyString dummy;
|
||||||
const auto& it=strings.find(index);
|
const auto& it=strings.find(index);
|
||||||
if (it == strings.end()) return dummy;
|
if (it == strings.end()) return dummy;
|
||||||
return it->second.str;
|
return it->second.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void use(const index_t& index)
|
static void use(const index_t& index)
|
||||||
{
|
{
|
||||||
@@ -77,7 +82,7 @@ class StringIndexer
|
|||||||
{
|
{
|
||||||
if (strings.find(index)==strings.end())
|
if (strings.find(index)==strings.end())
|
||||||
{
|
{
|
||||||
strings[index].str = std::string(str, len);
|
strings[index].str = TinyString(str, len);
|
||||||
strings[index].used++;
|
strings[index].used++;
|
||||||
// Serial << "Creating index " << index << " for (" << strings[index].str.c_str() << ") len=" << len << endl;
|
// Serial << "Creating index " << index << " for (" << strings[index].str.c_str() << ") len=" << len << endl;
|
||||||
return index;
|
return index;
|
||||||
@@ -86,7 +91,9 @@ class StringIndexer
|
|||||||
return 0; // TODO out of indexes
|
return 0; // TODO out of indexes
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::map<index_t, StringCounter> strings;
|
using Strings = std::unordered_map<index_t, StringCounter>;
|
||||||
|
|
||||||
|
static Strings strings;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IndexedString
|
class IndexedString
|
||||||
@@ -103,7 +110,7 @@ class IndexedString
|
|||||||
index=StringIndexer::strToIndex(str, len);
|
index=StringIndexer::strToIndex(str, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexedString(const std::string& str) : IndexedString(str.c_str(), str.length()) {};
|
IndexedString(const TinyString& str) : IndexedString(str.c_str(), str.length()) {};
|
||||||
|
|
||||||
~IndexedString() { StringIndexer::release(index); }
|
~IndexedString() { StringIndexer::release(index); }
|
||||||
|
|
||||||
@@ -124,7 +131,7 @@ class IndexedString
|
|||||||
return i1.index == i2.index;
|
return i1.index == i2.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& str() const { return StringIndexer::str(index); }
|
const TinyString& str() const { return StringIndexer::str(index); }
|
||||||
|
|
||||||
const StringIndexer::index_t& getIndex() const { return index; }
|
const StringIndexer::index_t& getIndex() const { return index; }
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ MqttClient::MqttClient(MqttBroker* local_broker, TcpClient* new_client)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
MqttClient::MqttClient(MqttBroker* local_broker, const std::string& id)
|
MqttClient::MqttClient(MqttBroker* local_broker, const TinyString& id)
|
||||||
: local_broker(local_broker), clientId(id)
|
: local_broker(local_broker), clientId(id)
|
||||||
{
|
{
|
||||||
alive = 0;
|
alive = 0;
|
||||||
@@ -97,7 +97,7 @@ void MqttClient::connect(MqttBroker* local)
|
|||||||
local_broker = local;
|
local_broker = local;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttClient::connect(std::string broker, uint16_t port, uint16_t ka)
|
void MqttClient::connect(TinyString broker, uint16_t port, uint16_t ka)
|
||||||
{
|
{
|
||||||
debug("MqttClient::connect_to_host " << broker << ':' << port);
|
debug("MqttClient::connect_to_host " << broker << ':' << port);
|
||||||
keep_alive = ka;
|
keep_alive = ka;
|
||||||
@@ -128,7 +128,7 @@ void MqttBroker::addClient(MqttClient* client)
|
|||||||
clients.push_back(client);
|
clients.push_back(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttBroker::connect(const std::string& host, uint16_t port)
|
void MqttBroker::connect(const TinyString& host, uint16_t port)
|
||||||
{
|
{
|
||||||
debug("MqttBroker::connect");
|
debug("MqttBroker::connect");
|
||||||
if (remote_broker == nullptr) remote_broker = new MqttClient;
|
if (remote_broker == nullptr) remote_broker = new MqttClient;
|
||||||
@@ -461,7 +461,7 @@ void MqttClient::processMessage(MqttMessage* mesg)
|
|||||||
|
|
||||||
// ClientId
|
// ClientId
|
||||||
mesg->getString(payload, len);
|
mesg->getString(payload, len);
|
||||||
clientId = std::string(payload, len);
|
clientId = TinyString(payload, len);
|
||||||
payload += len;
|
payload += len;
|
||||||
|
|
||||||
if (mqtt_flags & FlagWill) // Will topic
|
if (mqtt_flags & FlagWill) // Will topic
|
||||||
@@ -539,11 +539,11 @@ void MqttClient::processMessage(MqttMessage* mesg)
|
|||||||
payload = header+2;
|
payload = header+2;
|
||||||
|
|
||||||
debug("un/subscribe loop");
|
debug("un/subscribe loop");
|
||||||
std::string qoss;
|
TinyString qoss;
|
||||||
while(payload < mesg->end())
|
while(payload < mesg->end())
|
||||||
{
|
{
|
||||||
mesg->getString(payload, len); // Topic
|
mesg->getString(payload, len); // Topic
|
||||||
debug( " topic (" << std::string(payload, len) << ')');
|
debug( " topic (" << TinyString(payload, len) << ')');
|
||||||
// subscribe(Topic(payload, len));
|
// subscribe(Topic(payload, len));
|
||||||
Topic topic(payload, len);
|
Topic topic(payload, len);
|
||||||
|
|
||||||
@@ -597,7 +597,7 @@ void MqttClient::processMessage(MqttMessage* mesg)
|
|||||||
#if TINY_MQTT_DEBUG
|
#if TINY_MQTT_DEBUG
|
||||||
Console << "Received Publish (" << published.str().c_str() << ") size=" << (int)len << endl;
|
Console << "Received Publish (" << published.str().c_str() << ") size=" << (int)len << endl;
|
||||||
#endif
|
#endif
|
||||||
// << '(' << std::string(payload, len).c_str() << ')' << " msglen=" << mesg->length() << endl;
|
// << '(' << TinyString(payload, len).c_str() << ')' << " msglen=" << mesg->length() << endl;
|
||||||
if (qos) payload+=2; // ignore packet identifier if any
|
if (qos) payload+=2; // ignore packet identifier if any
|
||||||
len=mesg->end()-payload;
|
len=mesg->end()-payload;
|
||||||
// TODO reset DUP
|
// TODO reset DUP
|
||||||
@@ -889,7 +889,7 @@ void MqttMessage::hexdump(const char* prefix) const
|
|||||||
(void)prefix;
|
(void)prefix;
|
||||||
#if TINY_MQTT_DEBUG
|
#if TINY_MQTT_DEBUG
|
||||||
if (TinyMqtt::debug<2) return;
|
if (TinyMqtt::debug<2) return;
|
||||||
static std::map<Type, std::string> tts={
|
static std::map<Type, TinyString> tts={
|
||||||
{ Connect, "Connect" },
|
{ Connect, "Connect" },
|
||||||
{ ConnAck, "Connack" },
|
{ ConnAck, "Connack" },
|
||||||
{ Publish, "Publish" },
|
{ Publish, "Publish" },
|
||||||
@@ -902,7 +902,7 @@ void MqttMessage::hexdump(const char* prefix) const
|
|||||||
{ PingResp, "Pingresp" },
|
{ PingResp, "Pingresp" },
|
||||||
{ Disconnect, "Disconnect" }
|
{ Disconnect, "Disconnect" }
|
||||||
};
|
};
|
||||||
std::string t("Unknown");
|
TinyString t("Unknown");
|
||||||
Type typ=static_cast<Type>(buffer[0] & 0xF0);
|
Type typ=static_cast<Type>(buffer[0] & 0xF0);
|
||||||
if (tts.find(typ) != tts.end())
|
if (tts.find(typ) != tts.end())
|
||||||
t=tts[typ];
|
t=tts[typ];
|
||||||
@@ -919,7 +919,7 @@ void MqttMessage::hexdump(const char* prefix) const
|
|||||||
const char* hex_to_str = " | ";
|
const char* hex_to_str = " | ";
|
||||||
const char* separator = hex_to_str;
|
const char* separator = hex_to_str;
|
||||||
const char* half_sep = " - ";
|
const char* half_sep = " - ";
|
||||||
std::string ascii;
|
TinyString ascii;
|
||||||
|
|
||||||
Console << prefix << " size(" << buffer.size() << "), state=" << state << endl;
|
Console << prefix << " size(" << buffer.size() << "), state=" << state << endl;
|
||||||
|
|
||||||
|
|||||||
@@ -71,9 +71,10 @@ enum __attribute__((packed)) MqttError
|
|||||||
class Topic : public IndexedString
|
class Topic : public IndexedString
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Topic(const TinyString& m) : IndexedString(m){}
|
||||||
Topic(const char* s, uint8_t len) : IndexedString(s,len){}
|
Topic(const char* s, uint8_t len) : IndexedString(s,len){}
|
||||||
Topic(const char* s) : Topic(s, strlen(s)) {}
|
Topic(const char* s) : Topic(s, strlen(s)) {}
|
||||||
Topic(const std::string s) : Topic(s.c_str(), s.length()){};
|
// Topic(const TinyString s) : Topic(s.c_str(), s.length()){};
|
||||||
|
|
||||||
const char* c_str() const { return str().c_str(); }
|
const char* c_str() const { return str().c_str(); }
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ class MqttMessage
|
|||||||
void incoming(char byte);
|
void incoming(char byte);
|
||||||
void add(char byte) { incoming(byte); }
|
void add(char byte) { incoming(byte); }
|
||||||
void add(const char* p, size_t len, bool addLength=true );
|
void add(const char* p, size_t len, bool addLength=true );
|
||||||
void add(const std::string& s) { add(s.c_str(), s.length()); }
|
void add(const TinyString& s) { add(s.c_str(), s.length()); }
|
||||||
void add(const Topic& t) { add(t.str()); }
|
void add(const Topic& t) { add(t.str()); }
|
||||||
const char* end() const { return &buffer[0]+buffer.size(); }
|
const char* end() const { return &buffer[0]+buffer.size(); }
|
||||||
const char* getVHeader() const { return &buffer[vheader]; }
|
const char* getVHeader() const { return &buffer[vheader]; }
|
||||||
@@ -156,7 +157,7 @@ class MqttMessage
|
|||||||
private:
|
private:
|
||||||
void encodeLength();
|
void encodeLength();
|
||||||
|
|
||||||
std::string buffer;
|
TinyString buffer;
|
||||||
uint8_t vheader;
|
uint8_t vheader;
|
||||||
uint16_t size; // bytes left to receive
|
uint16_t size; // bytes left to receive
|
||||||
State state;
|
State state;
|
||||||
@@ -181,13 +182,13 @@ class MqttClient
|
|||||||
|
|
||||||
/** Constructor. Broker is the adress of a local broker if not null
|
/** Constructor. Broker is the adress of a local broker if not null
|
||||||
If you want to connect elsewhere, leave broker null and use connect() **/
|
If you want to connect elsewhere, leave broker null and use connect() **/
|
||||||
MqttClient(MqttBroker* broker = nullptr, const std::string& id = TINY_MQTT_DEFAULT_CLIENT_ID);
|
MqttClient(MqttBroker* broker = nullptr, const TinyString& id = TINY_MQTT_DEFAULT_CLIENT_ID);
|
||||||
MqttClient(const std::string& id) : MqttClient(nullptr, id){}
|
MqttClient(const TinyString& id) : MqttClient(nullptr, id){}
|
||||||
|
|
||||||
~MqttClient();
|
~MqttClient();
|
||||||
|
|
||||||
void connect(MqttBroker* local_broker);
|
void connect(MqttBroker* local_broker);
|
||||||
void connect(std::string broker, uint16_t port, uint16_t keep_alive = 10);
|
void connect(TinyString broker, uint16_t port, uint16_t keep_alive = 10);
|
||||||
|
|
||||||
// TODO it seems that connected returns true in tcp mode even if
|
// TODO it seems that connected returns true in tcp mode even if
|
||||||
// no negociation occurred
|
// no negociation occurred
|
||||||
@@ -202,8 +203,8 @@ class MqttClient
|
|||||||
if (tcp_client) tcp_client->write(buf, length);
|
if (tcp_client) tcp_client->write(buf, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& id() const { return clientId; }
|
const TinyString& id() const { return clientId; }
|
||||||
void id(const std::string& new_id) { clientId = new_id; }
|
void id(const TinyString& new_id) { clientId = new_id; }
|
||||||
|
|
||||||
/** Should be called in main loop() */
|
/** Should be called in main loop() */
|
||||||
void loop();
|
void loop();
|
||||||
@@ -221,7 +222,7 @@ class MqttClient
|
|||||||
MqttError publish(const Topic&, const char* payload, size_t pay_length);
|
MqttError publish(const Topic&, const char* payload, size_t pay_length);
|
||||||
MqttError publish(const Topic& t, const char* payload) { return publish(t, payload, strlen(payload)); }
|
MqttError publish(const Topic& t, const char* payload) { return publish(t, payload, strlen(payload)); }
|
||||||
MqttError publish(const Topic& t, const String& s) { return publish(t, s.c_str(), s.length()); }
|
MqttError publish(const Topic& t, const String& s) { return publish(t, s.c_str(), s.length()); }
|
||||||
MqttError publish(const Topic& t, const std::string& s) { return publish(t,s.c_str(),s.length());}
|
MqttError publish(const Topic& t, const TinyString& s) { return publish(t,s.c_str(),s.length());}
|
||||||
MqttError publish(const Topic& t) { return publish(t, nullptr, 0);};
|
MqttError publish(const Topic& t) { return publish(t, nullptr, 0);};
|
||||||
|
|
||||||
MqttError subscribe(Topic topic, uint8_t qos=0);
|
MqttError subscribe(Topic topic, uint8_t qos=0);
|
||||||
@@ -232,7 +233,7 @@ class MqttClient
|
|||||||
// TODO seems to be useless
|
// TODO seems to be useless
|
||||||
bool isLocal() const { return tcp_client == nullptr; }
|
bool isLocal() const { return tcp_client == nullptr; }
|
||||||
|
|
||||||
void dump(std::string indent="")
|
void dump(TinyString indent="")
|
||||||
{
|
{
|
||||||
(void)indent;
|
(void)indent;
|
||||||
#if TINY_MQTT_DEBUG
|
#if TINY_MQTT_DEBUG
|
||||||
@@ -298,7 +299,7 @@ class MqttClient
|
|||||||
|
|
||||||
TcpClient* tcp_client=nullptr; // connection to remote broker
|
TcpClient* tcp_client=nullptr; // connection to remote broker
|
||||||
std::set<Topic> subscriptions;
|
std::set<Topic> subscriptions;
|
||||||
std::string clientId;
|
TinyString clientId;
|
||||||
CallBack callback = nullptr;
|
CallBack callback = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -318,12 +319,12 @@ class MqttBroker
|
|||||||
void begin() { server->begin(); }
|
void begin() { server->begin(); }
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
void connect(const std::string& host, uint16_t port=1883);
|
void connect(const TinyString& host, uint16_t port=1883);
|
||||||
bool connected() const { return state == Connected; }
|
bool connected() const { return state == Connected; }
|
||||||
|
|
||||||
size_t clientsCount() const { return clients.size(); }
|
size_t clientsCount() const { return clients.size(); }
|
||||||
|
|
||||||
void dump(std::string indent="")
|
void dump(TinyString indent="")
|
||||||
{
|
{
|
||||||
for(auto client: clients)
|
for(auto client: clients)
|
||||||
client->dump(indent);
|
client->dump(indent);
|
||||||
|
|||||||
160
src/TinyString.cpp
Normal file
160
src/TinyString.cpp
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
#include "TinyString.h"
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
const char* TinyString::emptyString = "";
|
||||||
|
|
||||||
|
TinyString::TinyString(const char* buffer, uint16_t s)
|
||||||
|
{
|
||||||
|
dup(buffer, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
TinyString::TinyString(int i, int base)
|
||||||
|
{
|
||||||
|
reserve(sizeof(int)*8+1);
|
||||||
|
itoa(i, str, base);
|
||||||
|
size_ = strlen(str);
|
||||||
|
free_ -= size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
TinyString::TinyString(const TinyString& m)
|
||||||
|
{
|
||||||
|
copy(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
TinyString& TinyString::operator=(const TinyString& m)
|
||||||
|
{
|
||||||
|
copy(m);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TinyString& TinyString::operator+=(const char c)
|
||||||
|
{
|
||||||
|
push_back(c);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TinyString& TinyString::operator +=(int i)
|
||||||
|
{
|
||||||
|
reserve(size_ + sizeof(int)*3+1);
|
||||||
|
itoa(i, str + size_, 10);
|
||||||
|
int8_t sz = strlen(str+size_);
|
||||||
|
size_ += sz;
|
||||||
|
free_ -= sz;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TinyString::concat(const char* buf, uint16_t len)
|
||||||
|
{
|
||||||
|
reserve(size_ + len + 1);
|
||||||
|
strcpy(str + size_, buf);
|
||||||
|
size_ += len;
|
||||||
|
free_ -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TinyString::push_back(const char c)
|
||||||
|
{
|
||||||
|
reserve(size_+1, extent);
|
||||||
|
str[size_++] = c;
|
||||||
|
str[size_] = 0;
|
||||||
|
free_--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TinyString::erase(uint16_t pos, uint16_t size)
|
||||||
|
{
|
||||||
|
if (size == npos) size = size_;
|
||||||
|
if (pos > size_) return;
|
||||||
|
if (pos + size > size_) size = size_ - pos;
|
||||||
|
memmove(str+pos, str+pos+size, size_ - pos + 1);
|
||||||
|
if (size_ == size)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_ -= size;
|
||||||
|
free_ += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TinyString::clear()
|
||||||
|
{
|
||||||
|
if (size_)
|
||||||
|
free(str);
|
||||||
|
str = const_cast<char*>(emptyString); // Dangerous str must be left untouched when size_ == 0
|
||||||
|
size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TinyString& TinyString::operator = (const char c)
|
||||||
|
{
|
||||||
|
dup(&c, 1);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TinyString TinyString::substr(uint16_t pos, uint16_t size)
|
||||||
|
{
|
||||||
|
if (size == npos) size = size_;
|
||||||
|
if (pos > size_) return TinyString();
|
||||||
|
if (pos + size > size_) size = size_ - pos;
|
||||||
|
return TinyString(str+pos, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TinyString::starts_with(const char* buf, uint16_t size) const
|
||||||
|
{
|
||||||
|
const_iterator it(str);
|
||||||
|
while(size and it != end() and (*it == *buf))
|
||||||
|
{
|
||||||
|
it++;
|
||||||
|
buf++;
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
return size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TinyString::compare(const char* s, uint16_t len) const
|
||||||
|
{
|
||||||
|
if (len > size_)
|
||||||
|
return memcmp(str, s, size_ + 1);
|
||||||
|
else
|
||||||
|
return memcmp(str, s, len + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TinyString::reserve(uint16_t sz, uint8_t extent)
|
||||||
|
{
|
||||||
|
if (sz == 0)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (size_ == 0)
|
||||||
|
{
|
||||||
|
free_ = sz + extent;
|
||||||
|
str = static_cast<char*>(malloc(sz + extent));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((sz > size_ + free_) or (extent > size_ + free_ - sz))
|
||||||
|
{
|
||||||
|
free_ = sz + extent - size_;
|
||||||
|
str = static_cast<char*>(realloc(str, sz + extent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TinyString::collect()
|
||||||
|
{
|
||||||
|
if (size_ > 0 and free_ > 1)
|
||||||
|
{
|
||||||
|
str = static_cast<char*>(realloc(str, size_ + 1));
|
||||||
|
free_ = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TinyString::dup(const char* buffer, uint16_t sz, uint8_t extent)
|
||||||
|
{
|
||||||
|
reserve(sz + 1, extent);
|
||||||
|
memcpy(str, buffer, sz);
|
||||||
|
str[sz] = 0;
|
||||||
|
if (size_ > sz)
|
||||||
|
free_ += size_ - sz;
|
||||||
|
else
|
||||||
|
free_ -= sz - size_;
|
||||||
|
size_ = sz;
|
||||||
|
}
|
||||||
79
src/TinyString.h
Normal file
79
src/TinyString.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
class TinyString
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = char;
|
||||||
|
static constexpr uint16_t npos = std::numeric_limits<uint16_t>::max();
|
||||||
|
|
||||||
|
TinyString() = default;
|
||||||
|
TinyString(int, int base=10);
|
||||||
|
TinyString(const TinyString&);
|
||||||
|
TinyString(const char*, uint16_t size);
|
||||||
|
TinyString(const char* s) : TinyString(s, strlen(s)){};
|
||||||
|
TinyString& operator= (const TinyString&);
|
||||||
|
~TinyString() { clear(); }
|
||||||
|
|
||||||
|
int compare(const char* buf, uint16_t len) const;
|
||||||
|
int compare(const char* buf) const { return compare(buf, strlen(buf)); }
|
||||||
|
|
||||||
|
friend bool operator == (const TinyString& l, const TinyString& r) { return l.compare(r) == 0; }
|
||||||
|
|
||||||
|
friend bool operator < (const TinyString& l, const TinyString& r) { return l.compare(r) <0; }
|
||||||
|
|
||||||
|
const char* c_str() const { return str; }
|
||||||
|
uint16_t length() const { return size_; }
|
||||||
|
uint16_t size() const { return length(); }
|
||||||
|
void concat(const char* buf, uint16_t len);
|
||||||
|
|
||||||
|
bool starts_with(const char* buf, uint16_t len) const;
|
||||||
|
bool starts_with(const char* buf) const { return starts_with(buf, strlen(buf)); }
|
||||||
|
|
||||||
|
TinyString substr(uint16_t pos, uint16_t len = npos);
|
||||||
|
|
||||||
|
char& operator[](uint16_t index) const { assert(index < size_); return str[index]; }
|
||||||
|
TinyString& operator = (const char c);
|
||||||
|
TinyString& operator +=(const char c);
|
||||||
|
TinyString& operator +=(const char* buf) { concat(buf, strlen(buf)); return *this; }
|
||||||
|
TinyString& operator +=(const TinyString& s) { concat(s.str, s.size_); return *this; }
|
||||||
|
TinyString& operator +=(int32_t);
|
||||||
|
|
||||||
|
operator const char*() const { return str; }
|
||||||
|
|
||||||
|
void reserve(uint16_t size) { reserve(size, 0); }
|
||||||
|
|
||||||
|
void erase(uint16_t pos, uint16_t size = npos);
|
||||||
|
|
||||||
|
void dup(const char* buffer, uint16_t size, uint8_t extent = 4);
|
||||||
|
|
||||||
|
void push_back(const char c);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
using const_iterator = const char*;
|
||||||
|
using iterator = char*;
|
||||||
|
const_iterator cbegin() const { return begin(); }
|
||||||
|
const_iterator cend() const { return end(); }
|
||||||
|
iterator begin() const { return str; }
|
||||||
|
iterator end() const { return str + size_; }
|
||||||
|
|
||||||
|
uint16_t capacity() const { return size_ + free_; }
|
||||||
|
void collect(); // Save memory
|
||||||
|
|
||||||
|
private:
|
||||||
|
void reserve(uint16_t new_size, uint8_t extent);
|
||||||
|
void copy(const TinyString& t) { dup(t.str, t.size_); };
|
||||||
|
|
||||||
|
char* str = const_cast<char *>(emptyString);
|
||||||
|
uint16_t size_ = 0; // if size_ == 0 no allocation, but str = emptyString
|
||||||
|
uint8_t free_ = 0; // malloc(str) = size_ + free_
|
||||||
|
|
||||||
|
static const char* emptyString;
|
||||||
|
const uint8_t extent = 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
@@ -1,21 +1,29 @@
|
|||||||
|
SUB=
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
@set -e; \
|
@set -e; \
|
||||||
for i in $(SUB)*-tests/Makefile; do \
|
for i in $(SUB)*-tests/Makefile; do \
|
||||||
$(MAKE) -C $$(dirname $$i) -j clean; \
|
|
||||||
echo '==== Making:' $$(dirname $$i); \
|
echo '==== Making:' $$(dirname $$i); \
|
||||||
$(MAKE) -C $$(dirname $$i) -j; \
|
$(MAKE) -C $$(dirname $$i) -j; \
|
||||||
done
|
done
|
||||||
|
|
||||||
|
valgrind:
|
||||||
|
@set -e; \
|
||||||
|
$(MAKE) tests; \
|
||||||
|
for i in $(SUB)*-tests/Makefile; do \
|
||||||
|
echo '==== Running:' $$(dirname $$i); \
|
||||||
|
valgrind $$(dirname $$i)/$$(dirname $$i).out; \
|
||||||
|
done
|
||||||
|
|
||||||
debugtest:
|
debugtest:
|
||||||
@set -e; \
|
@set -e; \
|
||||||
$(MAKE) clean; \
|
$(MAKE) clean; \
|
||||||
$(MAKE) -C debug-mode -j; \
|
$(MAKE) -C debug-mode -j; \
|
||||||
debug-mode/debug-tests.out
|
debug-mode/debug-tests.out
|
||||||
|
|
||||||
runtests: debugtest
|
runtests:
|
||||||
@$(MAKE) clean
|
|
||||||
@$(MAKE) tests
|
|
||||||
@set -e; \
|
@set -e; \
|
||||||
|
$(MAKE) tests; \
|
||||||
for i in $(SUB)*-tests/Makefile; do \
|
for i in $(SUB)*-tests/Makefile; do \
|
||||||
echo '==== Running:' $$(dirname $$i); \
|
echo '==== Running:' $$(dirname $$i); \
|
||||||
$$(dirname $$i)/$$(dirname $$i).out; \
|
$$(dirname $$i)/$$(dirname $$i).out; \
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ void setup() {
|
|||||||
while(!Serial);
|
while(!Serial);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Serial.println("=============[ FAKE NETWORK TinyMqtt TESTS ]========================");
|
Serial.println("=============[ TinyMqtt class-bind TESTS ]========================");
|
||||||
|
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.begin("network", "password");
|
WiFi.begin("network", "password");
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
# See https://github.com/bxparks/EpoxyDuino for documentation about this
|
# See https://github.com/bxparks/EpoxyDuino for documentation about this
|
||||||
# Makefile to compile and run Arduino programs natively on Linux or MacOS.
|
# Makefile to compile and run Arduino programs natively on Linux or MacOS.
|
||||||
|
|
||||||
EXTRA_CXXFLAGS=-g3 -O0
|
include ../Makefile.opts
|
||||||
|
|
||||||
# Remove flto flag from EpoxyDuino (too many <optimized out>)
|
|
||||||
CXXFLAGS = -Wextra -Wall -std=gnu++11 -fno-exceptions -fno-threadsafe-statics
|
|
||||||
|
|
||||||
APP_NAME := local-tests
|
APP_NAME := local-tests
|
||||||
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsyncTCP TinyConsole
|
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsyncTCP TinyConsole
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ using namespace std;
|
|||||||
|
|
||||||
MqttBroker broker(1883);
|
MqttBroker broker(1883);
|
||||||
|
|
||||||
std::map<std::string, std::map<Topic, int>> published; // map[client_id] => map[topic] = count
|
std::map<TinyString, std::map<Topic, int>> published; // map[client_id] => map[topic] = count
|
||||||
|
|
||||||
const char* lastPayload;
|
const char* lastPayload;
|
||||||
size_t lastLength;
|
size_t lastLength;
|
||||||
@@ -40,7 +40,7 @@ test(local_client_should_unregister_when_destroyed)
|
|||||||
assertEqual(broker.clientsCount(), (size_t)0);
|
assertEqual(broker.clientsCount(), (size_t)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
test(local_client_do_not_disconnect_after_publishing)
|
test(local_client_do_not_disconnect_after_publishing_and_long_inactivity)
|
||||||
{
|
{
|
||||||
EpoxyTest::set_millis(0);
|
EpoxyTest::set_millis(0);
|
||||||
MqttBroker broker(1883);
|
MqttBroker broker(1883);
|
||||||
@@ -56,11 +56,16 @@ test(local_client_do_not_disconnect_after_publishing)
|
|||||||
sender.publish("test", "value");
|
sender.publish("test", "value");
|
||||||
broker.loop();
|
broker.loop();
|
||||||
|
|
||||||
EpoxyTest::add_seconds(60);
|
EpoxyTest::add_seconds(600);
|
||||||
client.loop();
|
client.loop();
|
||||||
sender.loop();
|
sender.loop();
|
||||||
broker.loop();
|
broker.loop();
|
||||||
|
|
||||||
|
sender.publish("test", "value");
|
||||||
|
broker.loop();
|
||||||
|
sender.loop();
|
||||||
|
broker.loop();
|
||||||
|
|
||||||
assertEqual(broker.clientsCount(), (size_t)2);
|
assertEqual(broker.clientsCount(), (size_t)2);
|
||||||
assertEqual(sender.connected(), true);
|
assertEqual(sender.connected(), true);
|
||||||
assertEqual(client.connected(), true);
|
assertEqual(client.connected(), true);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# See https://github.com/bxparks/EpoxyDuino for documentation about this
|
# See https://github.com/bxparks/EpoxyDuino for documentation about this
|
||||||
# Makefile to compile and run Arduino programs natively on Linux or MacOS.
|
# Makefile to compile and run Arduino programs natively on Linux or MacOS.
|
||||||
|
|
||||||
EXTRA_CXXFLAGS=-g3 -O0
|
include ../Makefile.opts
|
||||||
|
|
||||||
# Remove flto flag from EpoxyDuino (too many <optimized out>)
|
# Remove flto flag from EpoxyDuino (too many <optimized out>)
|
||||||
CXXFLAGS = -Wextra -Wall -std=gnu++11 -fno-exceptions -fno-threadsafe-statics
|
# CXXFLAGS = -Wextra -Wall -std=gnu++11 -fno-exceptions -fno-threadsafe-statics
|
||||||
|
|
||||||
APP_NAME := network-tests
|
APP_NAME := network-tests
|
||||||
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsyncTCP TinyConsole
|
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsyncTCP TinyConsole
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ String toString(const IPAddress& ip)
|
|||||||
|
|
||||||
MqttBroker broker(1883);
|
MqttBroker broker(1883);
|
||||||
|
|
||||||
std::map<std::string, std::map<Topic, int>> published; // map[client_id] => map[topic] = count
|
std::map<TinyString, std::map<Topic, int>> published; // map[client_id] => map[topic] = count
|
||||||
|
|
||||||
char* lastPayload = nullptr;
|
char* lastPayload = nullptr;
|
||||||
size_t lastLength;
|
size_t lastLength;
|
||||||
@@ -463,4 +463,5 @@ void loop() {
|
|||||||
aunit::TestRunner::run();
|
aunit::TestRunner::run();
|
||||||
|
|
||||||
if (Serial.available()) ESP.reset();
|
if (Serial.available()) ESP.reset();
|
||||||
|
published.clear(); // Avoid crash in unit tests due to exit handlers
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
# See https://github.com/bxparks/EpoxyDuino for documentation about this
|
# See https://github.com/bxparks/EpoxyDuino for documentation about this
|
||||||
# Makefile to compile and run Arduino programs natively on Linux or MacOS.
|
# Makefile to compile and run Arduino programs natively on Linux or MacOS.
|
||||||
|
|
||||||
EXTRA_CXXFLAGS=-g3 -O0
|
include ../Makefile.opts
|
||||||
|
|
||||||
# Remove flto flag from EpoxyDuino (too many <optimized out>)
|
|
||||||
CXXFLAGS = -Wextra -Wall -std=gnu++11 -fno-exceptions -fno-threadsafe-statics
|
|
||||||
|
|
||||||
APP_NAME := nowifi-tests
|
APP_NAME := nowifi-tests
|
||||||
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsyncTCP TinyConsole
|
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsyncTCP TinyConsole
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ using namespace std;
|
|||||||
|
|
||||||
MqttBroker broker(1883);
|
MqttBroker broker(1883);
|
||||||
|
|
||||||
std::map<std::string, std::map<Topic, int>> published; // map[client_id] => map[topic] = count
|
std::map<TinyString, std::map<Topic, int>> published; // map[client_id] => map[topic] = count
|
||||||
|
|
||||||
char* lastPayload = nullptr;
|
char* lastPayload = nullptr;
|
||||||
size_t lastLength;
|
size_t lastLength;
|
||||||
@@ -279,4 +279,5 @@ void loop() {
|
|||||||
aunit::TestRunner::run();
|
aunit::TestRunner::run();
|
||||||
|
|
||||||
if (Serial.available()) ESP.reset();
|
if (Serial.available()) ESP.reset();
|
||||||
|
published.clear(); // Avoid crash at exit handlers
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# See https://github.com/bxparks/EpoxyDuino for documentation about this
|
# See https://github.com/bxparks/EpoxyDuino for documentation about this
|
||||||
# Makefile to compile and run Arduino programs natively on Linux or MacOS.
|
# Makefile to compile and run Arduino programs natively on Linux or MacOS.
|
||||||
|
|
||||||
EXTRA_CXXFLAGS=-g3 -O0
|
include ../Makefile.opts
|
||||||
|
|
||||||
APP_NAME := string-indexer-tests
|
APP_NAME := string-indexer-tests
|
||||||
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsync TinyConsole
|
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsync TinyConsole
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ test(indexer_indexed_operator_eq)
|
|||||||
|
|
||||||
test(indexer_get_string)
|
test(indexer_get_string)
|
||||||
{
|
{
|
||||||
std::string sone("one");
|
TinyString sone("one");
|
||||||
IndexedString one(sone);
|
IndexedString one(sone);
|
||||||
|
|
||||||
assertTrue(sone==one.str());
|
assertTrue(sone==one.str());
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# See https://github.com/bxparks/EpoxyDuino for documentation about this
|
# See https://github.com/bxparks/EpoxyDuino for documentation about this
|
||||||
# Makefile to compile and run Arduino programs natively on Linux or MacOS.
|
# Makefile to compile and run Arduino programs natively on Linux or MacOS.
|
||||||
|
|
||||||
EXTRA_CXXFLAGS=-g3 -O0
|
include ../Makefile.opts
|
||||||
|
|
||||||
APP_NAME := topic-tests
|
APP_NAME := topic-tests
|
||||||
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsync TinyConsole
|
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsync TinyConsole
|
||||||
|
|||||||
Reference in New Issue
Block a user