fix compile errors
[wdl/wdl-ol.git] / WDL / assocarray.h
blobba90d9fcc23ceb4eec55e4e23676909cb10b2128
1 #ifndef _WDL_ASSOCARRAY_H_
2 #define _WDL_ASSOCARRAY_H_
4 #include "heapbuf.h"
7 // on all of these, if valdispose is set, the array will dispose of values as needed.
8 // if keydup/keydispose are set, copies of (any) key data will be made/destroyed as necessary
11 // WDL_AssocArrayImpl can be used on its own, and can contain structs for keys or values
12 template <class KEY, class VAL> class WDL_AssocArrayImpl
14 WDL_AssocArrayImpl(const WDL_AssocArrayImpl &cp) { CopyContents(cp); }
16 WDL_AssocArrayImpl &operator=(const WDL_AssocArrayImpl &cp) { CopyContents(cp); return *this; }
18 public:
20 explicit WDL_AssocArrayImpl(int (*keycmp)(KEY *k1, KEY *k2), KEY (*keydup)(KEY)=0, void (*keydispose)(KEY)=0, void (*valdispose)(VAL)=0)
22 m_keycmp = keycmp;
23 m_keydup = keydup;
24 m_keydispose = keydispose;
25 m_valdispose = valdispose;
28 ~WDL_AssocArrayImpl()
30 DeleteAll();
33 VAL* GetPtr(KEY key, KEY *keyPtrOut=NULL) const
35 bool ismatch = false;
36 int i = LowerBound(key, &ismatch);
37 if (ismatch)
39 KeyVal* kv = m_data.Get()+i;
40 if (keyPtrOut) *keyPtrOut = kv->key;
41 return &(kv->val);
43 return 0;
46 bool Exists(KEY key) const
48 bool ismatch = false;
49 LowerBound(key, &ismatch);
50 return ismatch;
53 int Insert(KEY key, VAL val)
55 bool ismatch = false;
56 int i = LowerBound(key, &ismatch);
57 if (ismatch)
59 KeyVal* kv = m_data.Get()+i;
60 if (m_valdispose) m_valdispose(kv->val);
61 kv->val = val;
63 else
65 KeyVal* kv = m_data.Resize(m_data.GetSize()+1)+i;
66 memmove(kv+1, kv, (m_data.GetSize()-i-1)*(unsigned int)sizeof(KeyVal));
67 if (m_keydup) key = m_keydup(key);
68 kv->key = key;
69 kv->val = val;
71 return i;
74 void Delete(KEY key)
76 bool ismatch = false;
77 int i = LowerBound(key, &ismatch);
78 if (ismatch)
80 KeyVal* kv = m_data.Get()+i;
81 if (m_keydispose) m_keydispose(kv->key);
82 if (m_valdispose) m_valdispose(kv->val);
83 m_data.Delete(i);
87 void DeleteByIndex(int idx)
89 if (idx >= 0 && idx < m_data.GetSize())
91 KeyVal* kv = m_data.Get()+idx;
92 if (m_keydispose) m_keydispose(kv->key);
93 if (m_valdispose) m_valdispose(kv->val);
94 m_data.Delete(idx);
98 void DeleteAll(bool resizedown=false)
100 if (m_keydispose || m_valdispose)
102 int i;
103 for (i = 0; i < m_data.GetSize(); ++i)
105 KeyVal* kv = m_data.Get()+i;
106 if (m_keydispose) m_keydispose(kv->key);
107 if (m_valdispose) m_valdispose(kv->val);
110 m_data.Resize(0, resizedown);
113 int GetSize() const
115 return m_data.GetSize();
118 VAL* EnumeratePtr(int i, KEY* key=0) const
120 if (i >= 0 && i < m_data.GetSize())
122 KeyVal* kv = m_data.Get()+i;
123 if (key) *key = kv->key;
124 return &(kv->val);
126 return 0;
129 KEY* ReverseLookupPtr(VAL val) const
131 int i;
132 for (i = 0; i < m_data.GetSize(); ++i)
134 KeyVal* kv = m_data.Get()+i;
135 if (kv->val == val) return &kv->key;
137 return 0;
140 void ChangeKey(KEY oldkey, KEY newkey)
142 bool ismatch=false;
143 int i = LowerBound(oldkey, &ismatch);
144 if (ismatch)
146 KeyVal* kv = m_data.Get()+i;
147 if (m_keydispose) m_keydispose(kv->key);
148 if (m_keydup) newkey = m_keydup(newkey);
149 kv->key = newkey;
150 Resort();
154 void ChangeKeyByIndex(int idx, KEY newkey, bool needsort)
156 if (idx >= 0 && idx < m_data.GetSize())
158 KeyVal* kv = m_data.Get()+idx;
159 if (m_keydispose) m_keydispose(kv->key);
160 if (m_keydup) newkey = m_keydup(newkey);
161 kv->key = newkey;
162 if (needsort) Resort();
166 // fast add-block mode
167 void AddUnsorted(KEY key, VAL val)
169 int i=m_data.GetSize();
170 KeyVal* kv = m_data.Resize(i+1)+i;
171 if (m_keydup) key = m_keydup(key);
172 kv->key = key;
173 kv->val = val;
176 void Resort()
178 if (m_data.GetSize() > 1 && m_keycmp)
180 qsort(m_data.Get(),m_data.GetSize(),sizeof(KeyVal),(int(*)(const void *,const void *))m_keycmp);
182 // AddUnsorted can add duplicate keys
183 // unfortunately qsort is not guaranteed to preserve order,
184 // ideally this filter would always preserve the last-added key
185 int i;
186 for (i=0; i < m_data.GetSize()-1; ++i)
188 KeyVal* kv=m_data.Get()+i;
189 KeyVal* nv=kv+1;
190 if (!m_keycmp(&kv->key, &nv->key))
192 DeleteByIndex(i--);
198 int LowerBound(KEY key, bool* ismatch) const
200 int a = 0;
201 int c = m_data.GetSize();
202 while (a != c)
204 int b = (a+c)/2;
205 KeyVal* kv=m_data.Get()+b;
206 int cmp = m_keycmp(&key, &kv->key);
207 if (cmp > 0) a = b+1;
208 else if (cmp < 0) c = b;
209 else
211 *ismatch = true;
212 return b;
215 *ismatch = false;
216 return a;
219 int GetIdx(KEY key) const
221 bool ismatch=false;
222 int i = LowerBound(key, &ismatch);
223 if (ismatch) return i;
224 return -1;
227 void SetGranul(int gran)
229 m_data.SetGranul(gran);
232 void CopyContents(const WDL_AssocArrayImpl &cp)
234 m_data=cp.m_data;
235 m_keycmp = cp.m_keycmp;
236 m_keydup = cp.m_keydup;
237 m_keydispose = m_keydup ? cp.m_keydispose : NULL;
238 m_valdispose = NULL; // avoid disposing of values twice, since we don't have a valdup, we can't have a fully valid copy
239 if (m_keydup)
241 int x;
242 const int n=m_data.GetSize();
243 for (x=0;x<n;x++)
245 KeyVal *kv=m_data.Get()+x;
246 if (kv->key) kv->key = m_keydup(kv->key);
251 void CopyContentsAsReference(const WDL_AssocArrayImpl &cp)
253 DeleteAll(true);
254 m_keydup = NULL; // this no longer can own any data
255 m_keydispose = NULL;
256 m_valdispose = NULL;
258 m_data=cp.m_data;
261 protected:
263 struct KeyVal
265 KEY key;
266 VAL val;
268 WDL_TypedBuf<KeyVal> m_data;
270 int (*m_keycmp)(KEY *k1, KEY *k2);
271 KEY (*m_keydup)(KEY);
272 void (*m_keydispose)(KEY);
273 void (*m_valdispose)(VAL);
278 // WDL_AssocArray adds useful functions but cannot contain structs for keys or values
279 template <class KEY, class VAL> class WDL_AssocArray : public WDL_AssocArrayImpl<KEY, VAL>
281 public:
283 explicit WDL_AssocArray(int (*keycmp)(KEY *k1, KEY *k2), KEY (*keydup)(KEY)=0, void (*keydispose)(KEY)=0, void (*valdispose)(VAL)=0)
284 : WDL_AssocArrayImpl<KEY, VAL>(keycmp, keydup, keydispose, valdispose)
288 VAL Get(KEY key, VAL notfound=0) const
290 VAL* p = this->GetPtr(key);
291 if (p) return *p;
292 return notfound;
295 VAL Enumerate(int i, KEY* key=0, VAL notfound=0) const
297 VAL* p = this->EnumeratePtr(i, key);
298 if (p) return *p;
299 return notfound;
302 KEY ReverseLookup(VAL val, KEY notfound=0) const
304 KEY* p=this->ReverseLookupPtr(val);
305 if (p) return *p;
306 return notfound;
311 template <class VAL> class WDL_IntKeyedArray : public WDL_AssocArray<int, VAL>
313 public:
315 explicit WDL_IntKeyedArray(void (*valdispose)(VAL)=0) : WDL_AssocArray<int, VAL>(cmpint, NULL, NULL, valdispose) {}
316 ~WDL_IntKeyedArray() {}
318 private:
320 static int cmpint(int *i1, int *i2) { return *i1-*i2; }
324 template <class VAL> class WDL_StringKeyedArray : public WDL_AssocArray<const char *, VAL>
326 public:
328 explicit WDL_StringKeyedArray(bool caseSensitive=true, void (*valdispose)(VAL)=0) : WDL_AssocArray<const char*, VAL>(caseSensitive?cmpstr:cmpistr, dupstr, freestr, valdispose) {}
330 ~WDL_StringKeyedArray() { }
332 static const char *dupstr(const char *s) { return strdup(s); } // these might not be necessary but depending on the libc maybe...
333 static int cmpstr(const char **s1, const char **s2) { return strcmp(*s1, *s2); }
334 static int cmpistr(const char **a, const char **b) { return stricmp(*a,*b); }
335 static void freestr(const char* s) { free((void*)s); }
336 static void freecharptr(char *p) { free(p); }
340 template <class VAL> class WDL_StringKeyedArray2 : public WDL_AssocArrayImpl<const char *, VAL>
342 public:
344 explicit WDL_StringKeyedArray2(bool caseSensitive=true, void (*valdispose)(VAL)=0) : WDL_AssocArrayImpl<const char*, VAL>(caseSensitive?cmpstr:cmpistr, dupstr, freestr, valdispose) {}
346 ~WDL_StringKeyedArray2() { }
348 static const char *dupstr(const char *s) { return strdup(s); } // these might not be necessary but depending on the libc maybe...
349 static int cmpstr(const char **s1, const char **s2) { return strcmp(*s1, *s2); }
350 static int cmpistr(const char **a, const char **b) { return stricmp(*a,*b); }
351 static void freestr(const char* s) { free((void*)s); }
352 static void freecharptr(char *p) { free(p); }
355 // sorts text as text, sorts anything that looks like a number as a number
356 template <class VAL> class WDL_LogicalSortStringKeyedArray : public WDL_StringKeyedArray<VAL>
358 public:
360 explicit WDL_LogicalSortStringKeyedArray(bool caseSensitive=true, void (*valdispose)(VAL)=0) : WDL_StringKeyedArray<VAL>(caseSensitive, valdispose)
362 WDL_StringKeyedArray<VAL>::m_keycmp = caseSensitive?cmpstr:cmpistr; // override
365 ~WDL_LogicalSortStringKeyedArray() { }
367 private:
369 static int cmpstr(const char **a, const char **b) { return _cmpstr(*a, *b, true); }
370 static int cmpistr(const char **a, const char **b) { return _cmpstr(*a, *b, false); }
372 static int _cmpstr(const char *s1, const char *s2, bool case_sensitive)
374 // this also exists as WDL_strcmp_logical in wdlcstring.h
375 char lastNonZeroChar=0;
376 // last matching character, updated if not 0. this allows us to track whether
377 // we are inside of a number with the same leading digits
379 for (;;)
381 char c1=*s1++, c2=*s2++;
382 if (!c1) return c1-c2;
384 if (c1!=c2)
386 if (c1 >= '0' && c1 <= '9' && c2 >= '0' && c2 <= '9')
388 int lzdiff=0, cnt=0;
389 if (lastNonZeroChar < '1' || lastNonZeroChar > '9')
391 while (c1 == '0') { c1=*s1++; lzdiff--; }
392 while (c2 == '0') { c2=*s2++; lzdiff++; } // lzdiff = lz2-lz1, more leading 0s = earlier in list
395 for (;;)
397 if (c1 >= '0' && c1 <= '9')
399 if (c2 < '0' || c2 > '9') return 1;
401 c1=s1[cnt];
402 c2=s2[cnt++];
404 else
406 if (c2 >= '0' && c2 <= '9') return -1;
407 break;
411 s1--;
412 s2--;
414 while (cnt--)
416 const int d = *s1++ - *s2++;
417 if (d) return d;
420 if (lzdiff) return lzdiff;
422 else
424 if (!case_sensitive)
426 if (c1>='a' && c1<='z') c1+='A'-'a';
427 if (c2>='a' && c2<='z') c2+='A'-'a';
429 if (c1 != c2) return c1-c2;
432 else if (c1 != '0') lastNonZeroChar=c1;
438 template <class VAL> class WDL_PtrKeyedArray : public WDL_AssocArray<INT_PTR, VAL>
440 public:
442 explicit WDL_PtrKeyedArray(void (*valdispose)(VAL)=0) : WDL_AssocArray<INT_PTR, VAL>(cmpptr, 0, 0, valdispose) {}
444 ~WDL_PtrKeyedArray() {}
446 private:
448 static int cmpptr(INT_PTR* a, INT_PTR* b) { const INT_PTR d = *a - *b; return d<0?-1:(d!=0); }
452 #endif