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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
// csl.c - Compact Sorted List
// A compact sorted list (CSL) is a data structure used to store a sorted list
// of strings compactly by reusing as many leading characters as possible from
// one list entry to the next. Each list entry may be followed by a fixed size
// payload, thereby making the data structure resemble a limited form of sorted
// hash table.
//
// The CSL is stored in memory as a sequence of entries. Each list entry
// consists of two values followed by characters followed by the fixed length
// payload, if any. The final list entry is followed by two zero values (with
// no trailing characters and no payload bytes).
//
// The first value of a list entry specifies the entry's head size. The head
// size is the number of leading characters from the previous list entry that
// are the same for the current list entry. The second value specifies the
// entry's tail size. The tail size is the number of trailing characters in
// the current list entry that differ from the previous list entry. The second
// value is then followed by those trailing characters, withOUT a terminating
// NUL character since the exact length is known. These trailing characters
// are followed by the fixed length payload, if any. The contents of the
// payload are not relevant to the CSL data structure itself. The payload
// bytes are opaque data provided by and returned to clients.
//
// The first entry in the list has no previous entry and therefore has an
// implicit head size of 0. Instead of storing zero there, the first entry's
// head size field is used to specify the fixed size of each entry's payload.
//
// Technically, the list entry strings need not be sorted, but unsorted list
// entries will reduce the compactness of the CSL so it is highly recommended
// to sort the list before compacting it into a CSL. Furthermore, unsorted
// entries will break search algorithms that depend on sorted entries.
//
// The CSL has certain characteristics that can affect its suitability for a
// given application. These are discussed here briefly:
//
// - Compact form
//
// The strings stored in a CSL are not so compact as a compression
// algorithm might be able to achieve, but they can be searched without
// having to uncompress them first.
//
// - Efficient searching
//
// The count of characters in common with the previous entry combined with
// the length of the new characters makes it fast to skip over entries that
// do not match the search string.
//
// - Self-contained/Relocatable
//
// The CSL is completely self-contained and uses no pointers so it can be
// located anywhere in memory.
//
// - Expensive inserts
//
// The sequential nature of the CSL makes inserts expensive. The CSL is
// therefore better suited for use with static (i.e. read-only) lists.
//
// This CSL implementation is designed for embedded systems with limited memory
// resources, so compactness is favored over generality. To that end, payload
// length value, the head size, and the tail size are each stored as a single
// byte. This limits the maximum size of the strings and payloads to 255 bytes
// each. This is an implementation limit, not an inherent limit of the CSL
// data structure.
//
// Example:
//
// The CSL for the following sorted list of keywords and one byte payloads is
// shown below.
//
// adc16_wb_ram1 1
// adc16_wb_ram2 2
// eq_0_gain 3
// eq_1_gain 4
// eth_0_bframes 5
// eth_0_core 6
//
// The CSL for that list would be stored as:
//
// 01 0D a d c 1 6 _ w b _ r a m 1 01
// 0C 01 2 02
// 00 09 e q _ 0 _ g a i n 03
// 03 06 1 _ g a i n 04
// 01 0C t h _ 0 _ b f r a m e s 05
// 06 04 c o r e 06
// 00 00
//
// Line breaks are added for clarity only. The CSL uses no string or line
// terminator characters. The compact representation, excluding payload which
// is not compacted and payload length value, occupies 58 bytes whereas the
// original representation, including terminating NULs, occupies 73 bytes.
// Searches the CSL pointed to by `csl` for the string `key`. If found, the
// returned pointer is non-null. If the CSL has non-zero payload length, the
// non-null pointer points to the first byte of payload corresponding to `key`.
const unsigned char *
// File static (private) static storage for csl_iter_* and find_by_* functions.
static const unsigned char *csl_pcsl = 0;
static unsigned char csl_key = ;
static unsigned char csl_pl_len = 0;
static unsigned char csl_nhead = 0;
// Initialize internal storage to iterate through a CSL
void
// Get the next entry. Returns pointer to payload of next entry or NULL if no
// more entries. If pkey is non-NULL, a pointer to the entry's full key string
// will be stored in *pkey.
const unsigned char *
// Searches a CSL for for the next entry whose payload byte `plidx` has value
// `plval`. If found, the returned pointer is non-null. If the CSL has
// non-zero payload length, this non-null pointer points to the first byte of
// payload corresponding to `key`.
//
// This function is designed to be called iteratively to walk through the
// entire CSL to find all matching the search criteria. To start a new search,
// `csl` should point to the beginning of the CSL to be searched using `plidx`
// and `plval` as the search criteria. If a matching entry is found and
// returned, the next matching entry can be found by passing NULL for `csl` and
// the desired search criteria for `plidx` and `plval`. While the most common
// use case will involve passing the same search criteria every time, the new
// search criteria are not required to be the same for each call.
const unsigned char *