forked from arendst/Tasmota
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsupport_light_list.ino
208 lines (180 loc) · 6.28 KB
/
support_light_list.ino
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
support_light_list.ino - Lightweight Linked List for simple objects - optimized for low code size and low memory
Copyright (C) 2021 Theo Arends and Stephan Hadinger
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*********************************************************************************************\
*
* private class for Linked List element
*
\*********************************************************************************************/
template <typename T>
class LList;
template <typename T>
class LList_elt {
public:
LList_elt() : _next(nullptr), _val() {}
inline T & val(void) { return _val; }
inline LList_elt<T> * next(void) { return _next; }
inline void next(LList_elt<T> * next) { _next = next; }
friend class LList<T>;
protected:
LList_elt<T> * _next;
T _val;
};
/*********************************************************************************************\
*
* Lightweight Linked List - optimized for low code size
*
\*********************************************************************************************/
template <typename T>
class LList {
public:
LList() : _head(nullptr) {}
~LList() { reset(); }
// remove elements
void removeHead(void); // remove first element
void reset(void); // remove all elements
void remove(const T * val);
// read the list
inline bool isEmpty(void) const { return (_head == nullptr) ? true : false; }
size_t length(void) const;
inline T * head(void) { return _head ? &_head->_val : nullptr; }
inline const T * head(void) const { return _head ? &_head->_val : nullptr; }
const T * at(size_t index) const ;
// non-const variants
// not very academic cast but reduces code size
inline T * at(size_t index) { return (T*) ((const LList<T>*)this)->at(index); }
// adding elements
T & addHead(void);
T & addHead(const T &val);
T & addToLast(void);
// add an element allocated externally
// memory is free by us now -- don't free it!
T & addHead(LList_elt<T> * elt);
T & addToLast(LList_elt<T> * elt);
// iterator
// see https://stackoverflow.com/questions/8164567/how-to-make-my-custom-type-to-work-with-range-based-for-loops
class iterator {
public:
iterator(LList_elt<T> *_cur): cur(_cur), next(nullptr) { if (cur) { next = cur->_next; } }
iterator operator++() { cur = next; if (cur) { next = cur->_next;} return *this; }
bool operator!=(const iterator & other) const { return cur != other.cur; }
T & operator*() const { return cur->_val; }
private:
LList_elt<T> *cur;
LList_elt<T> *next; // we need to keep next pointer in case the current attribute gets deleted
};
iterator begin() { return iterator(this->_head); } // start with 'head'
iterator end() { return iterator(nullptr); } // end with null pointer
// const iterator
class const_iterator {
public:
const_iterator(const LList_elt<T> *_cur): cur(_cur), next(nullptr) { if (cur) { next = cur->_next; } }
const_iterator operator++() { cur = next; if (cur) { next = cur->_next;} return *this; }
bool operator!=(const_iterator & other) const { return cur != other.cur; }
const T & operator*() const { return cur->_val; }
private:
const LList_elt<T> *cur;
const LList_elt<T> *next; // we need to keep next pointer in case the current attribute gets deleted
};
const_iterator begin() const { return const_iterator(this->_head); } // start with 'head'
const_iterator end() const { return const_iterator(nullptr); } // end with null pointer
protected:
LList_elt<T> * _head;
};
template <typename T>
size_t LList<T>::length(void) const {
size_t count = 0;
for (auto & elt : *this) { (void)elt; count++; }
return count;
}
template <typename T>
const T * LList<T>::at(size_t index) const {
size_t count = 0;
for (const auto & elt : *this) {
if (index == count++) { return &elt; }
}
return nullptr;
}
template <typename T>
void LList<T>::reset(void) {
while (_head) {
LList_elt<T> * next = _head->next();
delete _head;
_head = next;
}
}
template <typename T>
void LList<T>::removeHead(void) {
if (_head) {
LList_elt<T> * next = _head->next();
delete _head;
_head = next;
}
}
template <typename T>
void LList<T>::remove(const T * val) {
if (nullptr == val) { return; }
// find element in chain and find pointer before
LList_elt<T> **curr_ptr = &_head;
while (*curr_ptr) {
LList_elt<T> * curr_elt = *curr_ptr;
if ( &(curr_elt->_val) == val) {
*curr_ptr = curr_elt->_next; // update previous pointer to next element
delete curr_elt;
break; // stop iteration now
}
curr_ptr = &((*curr_ptr)->_next); // move to next element
}
}
template <typename T>
T & LList<T>::addHead(void) {
LList_elt<T> * elt = new LList_elt<T>(); // create element
elt->next(_head); // insert at the head
_head = elt;
return elt->_val;
}
template <typename T>
T & LList<T>::addHead(const T &val) {
LList_elt<T> * elt = new LList_elt<T>(); // create element
elt->next(_head); // insert at the head
elt->_val = val;
_head = elt;
return elt->_val;
}
template <typename T>
T & LList<T>::addHead(LList_elt<T> * elt) {
elt->next(_head); // insert at the head
_head = elt;
return elt->_val;
}
template <typename T>
T & LList<T>::addToLast(void) {
LList_elt<T> **curr_ptr = &_head;
while (*curr_ptr) {
curr_ptr = &((*curr_ptr)->_next);
}
LList_elt<T> * elt = new LList_elt<T>(); // create element
*curr_ptr = elt;
return elt->_val;
}
template <typename T>
T & LList<T>::addToLast(LList_elt<T> * elt) {
LList_elt<T> **curr_ptr = &_head;
while (*curr_ptr) {
curr_ptr = &((*curr_ptr)->_next);
}
*curr_ptr = elt;
elt->_next = nullptr;
return elt->_val;
}