-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStringIndexer.h
139 lines (121 loc) · 3.42 KB
/
StringIndexer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#pragma once
#include <map>
#include <string>
#include <string.h>
/***
Allows to store up to 255 different strings with one byte class
very memory efficient when one string is used many times.
*/
class StringIndexer
{
class StringCounter
{
std::string str;
uint8_t used = 0;
friend class StringIndexer;
#if EPOXY_DUINO
public:
// Workaround to avoid coredump in Indexer::release
// when destroying a Topic after the deletion of
// StringIndexer::strings map (which can occurs only with AUnit,
// never in the ESP itself, because ESP never ends)
// (I hate static vars)
~StringCounter() {
used = 255;
}
#endif
};
public:
using index_t = uint8_t;
static index_t strToIndex(const char* str, uint8_t len)
{
for (auto it = strings.begin(); it != strings.end(); it++)
{
if (strncmp(it->second.str.c_str(), str, len) == 0)
{
it->second.used++;
return it->first;
}
}
for (index_t index = 1; index; index++)
{
if (strings.find(index) == strings.end())
{
strings[index].str = std::string(str, len);
strings[index].used++;
// Serial << "Creating index " << index << " for (" << strings[index].str.c_str() << ") len=" << len << endl;
return index;
}
}
return 0; // TODO out of indexes
}
static const std::string& str(const index_t& index)
{
static std::string dummy;
const auto& it = strings.find(index);
if (it == strings.end()) return dummy;
return it->second.str;
}
static void use(const index_t& index)
{
auto it = strings.find(index);
if (it != strings.end()) it->second.used++;
}
static void release(const index_t& index)
{
auto it = strings.find(index);
if (it != strings.end())
{
it->second.used--;
if (it->second.used == 0)
{
strings.erase(it);
// Serial << "Removing string(" << it->second.str.c_str() << ") size=" << strings.size() << endl;
}
}
}
static uint16_t count() {
return strings.size();
}
private:
static std::map<index_t, StringCounter> strings;
};
class IndexedString
{
public:
IndexedString(const IndexedString& source)
{
StringIndexer::use(source.index);
index = source.index;
}
IndexedString(const char* str, uint8_t len)
{
index = StringIndexer::strToIndex(str, len);
}
IndexedString(const std::string& str) : IndexedString(str.c_str(), str.length()) {};
~IndexedString() {
StringIndexer::release(index);
}
IndexedString& operator=(const IndexedString& source)
{
StringIndexer::use(source.index);
index = source.index;
return *this;
}
friend bool operator<(const IndexedString& i1, const IndexedString& i2)
{
return i1.index < i2.index;
}
friend bool operator==(const IndexedString& i1, const IndexedString& i2)
{
return i1.index == i2.index;
}
const std::string& str() const {
return StringIndexer::str(index);
}
const StringIndexer::index_t& getIndex() const {
return index;
}
private:
StringIndexer::index_t index;
};