Make WvStreams compile with gcc 4.4.
[wvstreams.git] / include / uniconfkey.h
bloba4b8d76f385b5fdb4785108c4eccf3547815a0f8
1 /* -*- Mode: C++ -*-
2 * Worldvisions Weaver Software:
3 * Copyright (C) 2002 Net Integration Technologies, Inc.
4 *
5 * UniConfKeys are paths in the UniConf hierarchy.
6 */
7 #ifndef __UNICONFKEY_H
8 #define __UNICONFKEY_H
10 #include "wvstring.h"
11 #include "wvlinklist.h"
12 #include <limits.h>
15 /**
16 * Represents a UniConf key which is a path in a hierarchy structured much
17 * like the traditional Unix filesystem.
19 * - Segments in the path are delimited by slashes.
20 * - The empty string refers to the current level of the tree (eg. root).
21 * - Keys are case insensitive yet preserve case information.
22 * - Paired slashes are converted to single slashes.
23 * - Trailing slashes are discarded.
25 * The following paths are equivalent when canonicalized:
27 * - foo/key (the canonical representation)
28 * - Foo/Key (also canonical but preserves case)
29 * - /foo/key (converted to foo/key)
30 * - foo//key (converted to foo/key)
31 * - foo/key/ (converted to foo/key)
33 * Keys that may contain slashes or nulls should be escaped in some fashion
34 * prior to constructing a UniConfKey object. Simply prefixing slashes with
35 * backslashes is inadequate because UniConfKey does not give any special
36 * meaning to backslash.
38 class UniConfKey
40 class Segment : public WvString
42 public:
43 Segment() :
44 WvString(WvString::empty)
47 Segment(WvStringParm str) :
48 WvString((!str)? WvString::empty: str)
51 Segment(const Segment &segment) :
52 WvString(segment)
56 bool iswild() const
58 return *this == "*" || *this == "...";
62 class SegmentVector
64 int _size, _used;
65 Segment *vec;
66 public:
67 SegmentVector(int size) :
68 _size(size),
69 _used(0),
70 vec(new Segment[_size])
73 ~SegmentVector()
75 deletev vec;
78 void resize(int size, int shift = 0)
80 if (size <= _size)
82 if (shift > 0)
84 for (int i=_used-1; i>=0; --i)
85 vec[i+shift] = vec[i];
86 _used += shift;
88 return;
90 Segment *old_vec = vec;
91 vec = new Segment[size];
92 if (old_vec)
94 int limit = size-shift;
95 if (limit > _size)
96 limit = _size;
97 if (limit > _used)
98 limit = _used;
99 for (int i=0; i<limit; ++i)
100 vec[i+shift] = old_vec[i];
101 deletev old_vec;
103 _size = size;
104 _used += shift;
106 void zap()
108 _used = 0;
110 int size() const
112 return _size;
114 int used() const
116 return _used;
119 void append(const Segment &segment)
121 vec[_used++] = segment;
123 void append(WvStringParm string)
125 append(Segment(string));
127 void replace(int index, const Segment &segment)
129 vec[index] = segment;
130 if (index >= _used)
131 _used = index + 1;
133 void replace(int index, WvStringParm string)
135 replace(index, Segment(string));
137 const Segment &operator [](int index) const
139 return vec[index];
143 struct Store
145 SegmentVector segments;
146 int ref_count;
148 Store(int size, int _ref_count, WvStringParm key = WvString::null);
151 Store *store;
152 int left, right;
154 static Store EMPTY_store; /*!< represents "" (root) */
155 static Store ANY_store; /*!< represents "*" */
156 static Store RECURSIVE_ANY_store; /*!< represents "..." */
158 UniConfKey(Store *_store, int _left, int _right) :
159 store(_store),
160 left(_left),
161 right(_right)
163 store->ref_count++;
166 void unique();
167 void normalize();
168 UniConfKey &collapse();
170 public:
171 static UniConfKey EMPTY; /*!< represents "" (root) */
172 static UniConfKey ANY; /*!< represents "*" */
173 static UniConfKey RECURSIVE_ANY; /*!< represents "..." */
175 /** Constructs an empty UniConfKey (the 'root'). */
176 UniConfKey() :
177 store(&EMPTY_store),
178 left(0),
179 right(0)
181 store->ref_count++;
185 * Constructs a UniConfKey from a string.
187 * See the rules above for information about how the key string
188 * is canonicalized.
190 * "key" is the key as a string
192 UniConfKey(WvStringParm key) :
193 store(new Store(4, 1, key)),
194 left(0),
195 right(store->segments.used())
200 * Constructs a UniConfKey from a string.
202 * See the rules above for information about how the key string
203 * is canonicalized. This constructor only exists to help out the
204 * C++ compiler with its automatic type conversions.
206 * "key" is the key as a string
208 UniConfKey(const char *key) :
209 store(new Store(4, 1, WvFastString(key))),
210 left(0),
211 right(store->segments.used())
215 /** Constructs a UniConfKey from an int. */
216 UniConfKey(int key) :
217 store(new Store(1, 1, WvFastString(key))),
218 left(0),
219 right(store->segments.used())
224 * Copies a UniConfKey.
225 * "other" is the key to copy
227 UniConfKey(const UniConfKey &other) :
228 store(other.store),
229 left(other.left),
230 right(other.right)
232 store->ref_count++;
236 * Constructs a UniConfKey by concatenating two keys.
237 * "path" is the initial part of the new path
238 * "key" is the tail of the new path
240 UniConfKey(const UniConfKey &path, const UniConfKey &key);
242 ~UniConfKey()
244 if (--store->ref_count == 0)
245 delete store;
249 * Appends a path to this path.
250 * "other" is the path
252 void append(const UniConfKey &other);
255 * Prepends a path to this path.
256 * "other" is the path
258 void prepend(const UniConfKey &other);
261 * Returns true if this path has zero segments (also known as root).
262 * Returns: numsegments() == 0
264 bool isempty() const
266 return right == left;
269 /** Returns true if the key contains a wildcard. */
270 bool iswild() const;
272 /** Returns true if the key has a trailing slash. */
273 bool hastrailingslash() const
275 return right > left && !store->segments[right-1];
279 * Returns the number of segments in this path.
281 * The number of segments is equal to the number of slashes
282 * in the path unless the path is "/" (the root), which has
283 * zero segments.
285 * Returns: the number of segments
287 int numsegments() const
289 return right - left;
293 * Returns the specified segment of the path.
294 * "i" is the segment index
295 * Returns: the segment
297 UniConfKey segment(int n) const
299 return range(n, n + 1);
303 * Returns the path formed by the first n segments of this path and
304 * removes them from the key.
305 * Returns: the path
307 UniConfKey pop(int n = 1);
310 * Returns the path formed by the n first segments of this path.
311 * "n" is the number of segments
312 * Returns: the path
314 UniConfKey first(int n = 1) const
316 return range(0, n);
320 * Returns the path formed by the n last segments of this path.
321 * "n" is the number of segments
322 * Returns: the path
324 UniConfKey last(int n = 1) const
326 return range(numsegments() - n, INT_MAX);
330 * Returns the path formed by removing the first n segments of
331 * this path.
332 * "n" is the number of segments
333 * Returns: the path
335 UniConfKey removefirst(int n = 1) const
337 return range(n, INT_MAX);
341 * Returns the path formed by removing the last n segments of
342 * this path.
343 * "n" is the number of segments
344 * Returns: the path
346 UniConfKey removelast(int n = 1) const
348 return range(0, numsegments() - n);
352 * Returns a range of segments.
353 * "i" is the first segment index, beginning if <= 0
354 * "j" is the last segment index, end if >= numsegments()
355 * Returns: the path, empty if j <= i
357 UniConfKey range(int i, int j) const;
360 * Returns the canonical string representation of the path.
362 * If the UniConfKey was constructed in part or whole from
363 * strings, then the string returned here will have the same
364 * case information as those strings but the arrangement of
365 * slashes may differ. That is, the identity
366 * UniConfKey(string).printable() == string does not hold.
368 * Returns: the path as a string
370 WvString printable() const;
371 operator WvString() const
372 { return printable(); }
375 * Returns a (const char *) of printable() directly.
377 const char *cstr() const
378 { return printable(); }
381 * Assigns this path to equal another.
382 * "other" is the other path
384 UniConfKey &operator= (const UniConfKey &other)
386 if (--store->ref_count == 0)
387 delete store;
388 store = other.store;
389 left = other.left;
390 right = other.right;
391 ++store->ref_count;
392 return *this;
396 * Compares two paths lexicographically.
397 * Uses case-insensitive matching on the path string to produce
398 * a total ordering of all paths.
399 * "other" is the other path
400 * Returns: 0 if *this == other, < 0 if *this < other, else > 0
402 int compareto(const UniConfKey &other) const;
405 * Determines if the key matches a pattern.
406 * Patterns are simply keys that may have path segments consiting
407 * entirely of "*". Optional path segments are indicated by
408 * the segment "..." which matches zero or more segments.
410 * Using wildcards to represent part of a segment is not supported yet.
411 * "pattern" is the pattern
412 * Returns: true if the key matches, false otherwise
414 bool matches(const UniConfKey &pattern) const;
418 * Returns true if 'key' is a the same, or a subkey, of this UniConfKey.
420 bool suborsame(const UniConfKey &key) const;
421 bool suborsame(const UniConfKey &key, UniConfKey &subkey) const;
424 * If this UniConfKey is a subkey of 'key', then return the subkey
425 * portion. Behaviour is undefined when this is not the same. Use
426 * suborsame() to check.
428 UniConfKey subkey(const UniConfKey &key) const;
431 * Determines if two paths are equal.
432 * "other" is the other path
433 * Returns: true in that case
435 bool operator== (const UniConfKey &other) const
436 { return compareto(other) == 0; }
439 * Determines if two paths are unequal.
440 * "other" is the other path
441 * Returns: true in that case
443 bool operator!= (const UniConfKey &other) const
444 { return compareto(other) != 0; }
447 * Determines if this path precedes the other lexicographically.
448 * "other" is the other path
449 * Returns: true in that case
451 bool operator< (const UniConfKey &other) const
452 { return compareto(other) < 0; }
454 class Iter;
456 friend unsigned WvHash(const UniConfKey &k);
460 DeclareWvList(UniConfKey);
462 /** An iterator over the segments of a key. */
463 class UniConfKey::Iter
465 const UniConfKey &key;
466 int seg, max;
467 UniConfKey curseg;
469 public:
470 Iter(const UniConfKey &_key) : key(_key)
473 void rewind()
474 { seg = -1; max = key.numsegments(); }
476 bool cur()
477 { return seg >= 0 && seg < max; }
479 bool next()
480 { seg++; curseg = key.segment(seg); return cur(); }
482 const UniConfKey *ptr() const
483 { return &curseg; }
485 WvIterStuff(const UniConfKey);
488 #endif // __UNICONFKEY_H