1
# if ! defined(TS_CONFIG_VALUE_HEADER)
2
# define TS_CONFIG_VALUE_HEADER
6
TS Configuration API definition.
8
Copyright 2010 Network Geographics, Inc.
10
Licensed under the Apache License, Version 2.0 (the "License");
11
you may not use this file except in compliance with the License.
12
You may obtain a copy of the License at
14
http://www.apache.org/licenses/LICENSE-2.0
16
Unless required by applicable law or agreed to in writing, software
17
distributed under the License is distributed on an "AS IS" BASIS,
18
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
See the License for the specific language governing permissions and
20
limitations under the License.
23
# include <TsBuffer.h>
24
# include <NumericType.h>
25
# include <IntrusivePtr.h>
29
namespace ts { namespace config {
36
/** Class to provide a "pseudo bool" value.
37
This is used as the return type for the positive logical operator
38
(the converse of @c operator! ). This makes a class directly
39
usable in logical expressions. It is like a pointer but @b not
40
convertible to anything else, and so avoiding any undesirable
41
automatic conversions and the resulting ambiguities.
44
typedef bool (PseudoBool::*Type)() const; ///< The type itself.
45
bool operator ! () const; ///< A method to use for the @c true value.
46
static Type const TRUE; ///< The @c true equivalent.
47
static Type const FALSE; ///< The @c false equivalent.
53
VoidValue, ///< No value, invalid.
54
ListValue, ///< List of values.
55
GroupValue, ///< Group of values.
56
StringValue, ///< Text string.
57
IntegerValue, ///< Integer.
59
// Update N_VALUE_TYPES if you change the last enum value !!
61
/// Number of value types.
62
static size_t const N_VALUE_TYPES = PathValue + 1;
64
/** A path to a value in a configuration.
69
class ImplType : public IntrusivePtrCounter {
72
ImplType(); ///< Constructor.
74
/** Container for path elements.
75
We are subtle with our elements, which can be either a string
76
or a numeric index. By convention, if the pointer in the buffer is
77
@c NULL, then the size is a numeric index. Otherwise it's a name.
79
typedef std::vector<ConstBuffer> Elements;
80
Elements _elements; ///< Path elements.
83
typedef Path self; ///< Self reference type.
85
Path(); ///< Default constructor.
87
/// Append a string tag to the path.
89
ConstBuffer const& tag ///< Text of tag.
91
/// Append a numeric index to the path.
93
size_t idx ///< Index.
95
/// Reset to default constructed state.
98
/// Get the number of elements in this path.
101
/// Access an element by @a index.
102
ConstBuffer const& operator [] (
103
size_t index ///< Element index.
106
/** Parser for path text.
107
This is restartable so a path can be parsed in pieces.
108
@internal Sadly, FLEX is just too much overhead to be useful here.
112
typedef Parser self; ///< Self reference type.
114
Parser(); ///< Default constructor.
115
/** Construct with input.
117
This default constructs the Parser then calls @c setInput with
118
@a text. It is provided as a convenience as that will be the
124
ConstBuffer const& text ///< Input text.
127
/** Set the input @a text.
128
Parsing state is reset and the next parsing call will
129
start at the beginning of @a text.
132
ConstBuffer const& text ///< Input buffer.
137
ERROR, ///< Bad input.
139
INDEX, ///< Path index.
140
EOP, ///< End Of Path.
143
/** Parse the next element in the path.
145
@a cbuff may be @c NULL in which case no data about elements
146
is available. In general this should be called until @c EOP
147
or @c ERROR is returned, each call returning the next element.
149
@return A parse @c Result.
150
- TAG: A tag was found. The start and length are stored in @a cbuff.
151
- INDEX: An index was found. The value is in @a cbuff._size.
152
- EOP: No more path elements were found. Do not continue parsing.
153
- ERROR: A syntax error was encountered. See the errata for detail. Do not continue parsing.
156
ConstBuffer* cbuff = 0 ///< [out] Parsed path element.
159
/// Check if input is available.
160
bool hasInput() const;
163
ConstBuffer _input; ///< Current input buffer.
164
char const* _c; ///< Next input character.
167
typedef IntrusivePtr<ImplType> ImplPtr; ///< Smart pointer to implementation.
168
ImplPtr _ptr; ///< Our instance.
169
/// Force an implementation instance and return a pointer to it.
170
ImplType* instance();
174
/// Null buffer, handy in several places.
175
extern Buffer const NULL_BUFFER;
176
/// Null buffer, handy in several places.
177
extern ConstBuffer const NULL_CONST_BUFFER;
178
/// Index type for value items in the global table.
179
typedef NumericType<size_t, struct ValueIndexTag> ValueIndex;
180
/// Index value that presents NULL (invalid value).
181
static ValueIndex const NULL_VALUE_INDEX = static_cast<ValueIndex::raw_type>(-1);
182
/// Numeric type for configuration generation.
183
typedef NumericType<size_t, struct GenerationTag> Generation;
185
/** Value type properties.
186
These are used as bit masks on elements of an array.
188
static unsigned int const IS_VALID = 1;
189
static unsigned int const IS_LITERAL = 1<<1;
190
static unsigned int const IS_CONTAINER = 1<<2;
192
/// Value type property table.
193
extern unsigned int const Type_Property[N_VALUE_TYPES];
195
/** A value in the configuration.
196
This is used in a global table so it handles all types of Values.
197
Members that are not used for scalars are designed to be @c NULL
198
pointers in that case.
201
// Apparently the C++ standard, 7.3.1.2, states that unqualified
202
// friend classes only considers the current namespace, not any
203
// outer ones. So we have to fully qualify this. Blech.
204
friend class ts::config::Value;
205
friend class ValueTable;
207
/// Default constructor.
209
/// Construct empty item of a specific type.
210
ValueItem(ValueType type);
212
ValueType getType() const;
214
ValueType _type; ///< Type of value.
215
ValueIndex _parent; ///< Table index of parent value.
216
ConstBuffer _text; ///< Text of value (if scalar).
217
ConstBuffer _name; ///< Local name of value, if available.
218
size_t _local_index; ///< Index among siblings.
219
int _srcLine; ///< Source line.
220
int _srcColumn; ///< Source column.
222
/// Container for children of this item.
223
typedef std::vector<ValueIndex> ChildGroup;
224
/// Child items of this item.
225
ChildGroup _children;
229
// This is for optimizing named access at some point in the future.
230
/// Hold a child item name in a table for fast lookup.
232
ConstBuffer _text; ///< Text of name.
233
ValueIndex _index; ///< Index of child.
235
/// Container for child names.
236
typedef std::vector<Name> NameGroup;
237
/** Child names, if appropriate.
238
This is faulted in when needed, if this value is an aggregate with
239
named children. The list must be sorted on name so that it can be binary
240
searched for performance.
247
/** Table of configuration values.
248
This holds all the values for a specific configuration.
250
class ValueTableImpl : public IntrusivePtrCounter {
251
friend class ValueTable;
253
typedef ValueTableImpl self; ///< Self reference type.
255
ValueTableImpl(); ///< Constructor.
256
~ValueTableImpl(); ///< Destructor.
258
/// Container for value items.
259
typedef std::vector<ValueItem> ItemTable;
260
ItemTable _values; ///< All configuration values.
261
Generation _generation; ///< Generation number of configuration.
262
/// A group of buffers.
263
typedef std::vector<Buffer> BufferGroup;
264
/** Locally allocated buffers.
265
These are freed when this object is destroyed.
267
BufferGroup _buffers;
269
static ValueItem NULL_ITEM; ///< Null item for invalid access return.
272
/** Wrapper class for a table of configuration values.
273
@internal Really, this should be merged in to Configuration. The original
274
differences have evolved out of the implementation.
278
typedef ValueTable self; ///< Self reference type.
279
typedef ValueTableImpl ImplType; ///< Implementation type.
282
/// @return The number of value items in the table.
285
/// @return The generation number.
286
Generation generation() const;
288
/// Const access by index.
289
/// @return The value item at index @a idx.
290
ValueItem const& operator [] (
291
ValueIndex idx ///< Index of item.
294
/// @return The value item at index @a idx.
295
ValueItem& operator [] (
296
ValueIndex idx ///< Index of item.
299
/// Force the existence of the root item in the table.
300
/// @return @c this object.
301
self& forceRootItem();
302
/** Create a new item (value) with optional @a name
303
The table must contain @a parent. If @a name is omitted, the item
305
@return Index of the new value item.
308
ValueIndex parent, ///< Index of parent for item.
309
ValueType type, ///< Type of item.
310
ConstBuffer const& name = NULL_BUFFER ///< Name (may be empty).
313
/// Test for not table existence.
314
/// @return @c false if the implementation instance exists, @c true if not.
315
bool operator ! () const;
316
/// Test for table existence.
317
/// @return @c true if the implementation instance exists, @c false if not.
318
operator PseudoBool::Type() const;
319
/// Reset to default constructed state.
320
/// @return @c this object.
323
/** Allocate a local buffer.
324
This buffer will persist until the implementation instance
326
@return The allocated buffer.
328
Buffer alloc(size_t n);
330
typedef IntrusivePtr<ImplType> ImplPtr; ///< Smart pointer to implementation instance.
331
ImplPtr _ptr; ///< Implementation instance.
333
/// Force an implementation instance and return a pointer to it.
334
ImplType* instance();
336
} // namespace detail
338
/** Container for a configuration.
339
This is a wrapper class that holds a shared reference to a configuration.
341
class Configuration {
344
typedef Configuration self; ///< Self reference type.
346
/** Check if configuration is (not) valid.
347
@return @c true if this configuration is invalid, @c false otherwise.
349
bool operator ! () const;
350
/** Check if the configuration is valid.
351
@return The equivalent of @c true if this does @b not contain a value,
352
the equivalent of @c false if it does.
354
operator detail::PseudoBool::Type () const;
355
/** Get the root @c Value of the configuration.
356
The root is always a group and has no name.
357
@return The root value.
359
Value getRoot() const;
361
/// Get the number of child values on the root value.
362
size_t childCount() const;
363
/** Root value child access by @a index
364
@return The child or a @c Void value if there is no child with @a name.
367
size_t idx ///< Index of child value.
369
/** Root value child access by @a name.
370
@return The child or a @c Void value if there is no child with @a name.
373
ConstBuffer const& name
375
/** Root value child access by @a name.
376
@return The child or a @c Void value if there is no child with @a name.
379
char const* name ///< Null terminated string.
383
@return The value if found, an void valid if not.
386
char const* path ///< configuration path to value.
388
/** Load a configuration from a file.
390
@note Check the returned errata for problems during configuration
391
load. It is probably not a good idea to use the configuration in
392
any error are reported.
393
@return A new @c Configuration and errata.
395
static Rv<self> loadFromPath(
396
char const* path ///< file system path.
398
/** Allocate a local buffer of size @a n.
399
This buffer will persist until the implementation instance
401
@return The allocated buffer.
404
size_t n ///< requested size of buffer.
407
detail::ValueTable _table; ///< Table of values from the configuration.
410
/** This holds a value from the configuration.
412
@internal It is critical that none of the type specific subclasses define any data members
413
so that instances can be freely converted to and from this base class.
416
friend class Configuration;
418
typedef Value self; ///< Self reference type.
419
/// Default constructors.
420
/// Creates an @c NULL instance.
425
/// Get the type of value.
426
ValueType getType() const;
427
/// Test if this is a valid value.
428
/// @return @c true if this contains a value, @c false otherwise.
429
bool hasValue() const;
430
/** Operator form of @c hasValue.
432
@return @c true if this does @b not contain a value, @c false if it does.
434
bool operator ! () const;
435
/** Logical form of @c hasValue for use in logical expressions.
437
@return The equivalent of @c true if this does @b not contain a value,
438
the equivalent of @c false if it does.
440
operator detail::PseudoBool::Type () const;
442
/** Get the value text.
443
@return The text in the configuration file for this item if the item
444
is a scalar, an empty buffer otherwise.
446
ConstBuffer const& getText() const;
447
/// Set the @a text for this value.
449
ConstBuffer const& text
453
This gets the local name of the value. That is the name by which it
454
is known to its parent container.
456
@internal Only works for groups now. It should be made to work
457
for lists. This would require allocating strings for each index,
458
which should be shared across values. For instance, all values
459
at index 1 should return the same string "1", not separately
460
allocated for each value.
462
ConstBuffer const& getName() const;
464
This gets the local index for the value. This is the index which,
465
if used on the parent, would yield this value.
466
@return The local index.
468
size_t getIndex() const;
470
/// Test for a literal value.
471
/// @return @c true if the value is a literal,
472
/// @c false if it is a container or invalid.
473
bool isLiteral() const;
474
/// Test for value container.
475
/// @return @c true if the value is a container (can have child values),
476
/// @c false otherwise.
477
bool isContainer() const;
478
/// Get the parent value.
479
Value getParent() const;
480
/// Test if this is the root value for the configuration.
483
/// Get the number of child values.
484
size_t childCount() const;
485
/** Child access by @a index
486
@return The child or a @c Void value if there is no child with @a name.
489
size_t idx ///< Index of child value.
491
/** Child access by @a name.
492
@return The child or a @c Void value if there is no child with @a name.
495
ConstBuffer const& name
497
/** Child access by @a name.
498
@return The child or a @c Void value if there is no child with @a name.
501
char const* name ///< Null terminated string.
504
/** @name Creating child values.
506
These methods all take an optional @a name argument. This is
507
required if @c this is a @c Group and ignored if @c this is a @c
510
These methods will fail if
511
- @c this is not a container.
512
- @c this is a @c Group and no @a name is provided.
514
@note Currently for groups, duplicate names are not
515
detected. The duplicates will be inaccessible by name but can
516
still be found by index. This is a problem but I am still
517
pondering the appropriate solution.
520
@return The new value, or an invalid value plus errata on failure.
522
@internal I original had this as a single method, but changed to
523
separate per type. Overall less ugly because we can get the
524
arguments more useful.
527
/// Create a @c String value.
528
Rv<Value> makeString(
529
ConstBuffer const& text, ///< String content.
530
ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
532
/// Create an @c Integer value.
533
Rv<Value> makeInteger(
534
ConstBuffer const& text, ///< Text of number.
535
ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
537
/// Create a @c Group value.
539
ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
541
/// Create a @c List value.
543
ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
545
/// Create a @c Path value.
547
Path const& path, ///< Path.
548
ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
550
/// Create a child by type.
551
/// Client must fill in any other required elements.
553
ValueType type, ///< Type of child.
554
ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
559
@return The value if found, an void valid if not.
562
ConstBuffer const& path ///< Path relative to this value.
565
@return The value if found, an void valid if not.
568
char const* path ///< Path relative to this value.
570
/** Find a value using a precondensed path.
571
@return The value if found, an void valid if not.
574
Path const& path ///< Path relative to this value.
577
/** Reset to default constructed state.
578
@note This wrapper is reset, the value in the configuration is unchanged.
579
@return @c this object.
584
/// @return @c this object.
586
int line ///< Line in source stream.
588
/// Set source column.
589
/// @return @c this object.
590
self& setSourceColumn(
591
int col ///< Column in source stream.
593
/// Set the source location.
595
int line, ///< Line in source stream.
596
int col ///< Column in source stream.
599
/// @return The line in the source stream for this value.
600
int getSourceLine() const;
601
/// Get source column.
602
/// @return The column in the source stream for this value.
603
int getSourceColumn() const;
606
// Note: We store an index and not a pointer because a pointer will go stale
607
// if any items are added or removed from the underlying table.
608
// Also, by storing the configuration, we hold it in memory as long as a Value
609
// is in client hands.
610
Configuration _config; ///< The configuration for this value.
611
detail::ValueIndex _vidx; ///< Index of item.
613
static Buffer const NULL_BUFFER; ///< Empty buffer to return on method failures.
615
/// Construct from raw data.
617
Configuration cfg, ///< Source configuration.
618
detail::ValueIndex vidx ///< Index of value.
621
/** Get raw item pointer.
622
@note This pointer is unstable and must be recomputed on each method invocation.
623
@return The item pointer or @c NULL if this value is invalid.
625
detail::ValueItem* item();
626
/** Get constant raw item pointer.
627
@note This pointer is unstable and must be recomputed on each method invocation.
628
@return The item pointer or @c NULL if this value is invalid.
630
detail::ValueItem const* item() const;
635
inline bool ValueTable::operator ! () const { return ! _ptr; }
636
inline ValueTable::operator PseudoBool::Type () const { return _ptr ? PseudoBool::TRUE : PseudoBool::FALSE; }
637
inline size_t ValueTable::size() const { return _ptr ? _ptr->_values.size() : 0; }
638
inline Generation ValueTable::generation() const { return _ptr ? _ptr->_generation : Generation(0); }
639
inline ValueItem const& ValueTable::operator [] (ValueIndex idx) const { return const_cast<self*>(this)->operator [] (idx); }
640
inline ValueTable& ValueTable::reset() { _ptr = 0; return *this; }
642
inline ValueItem::ValueItem() : _type(VoidValue), _text(0,0), _name(0,0) {}
643
inline ValueItem::ValueItem(ValueType type) : _type(type), _text(0,0), _name(0,0) {}
644
inline ValueType ValueItem::getType() const { return _type; }
647
inline Value::~Value() { }
648
inline Value::Value() : _vidx(detail::NULL_VALUE_INDEX) {}
649
inline Value::Value(Configuration cfg, detail::ValueIndex vidx) : _config(cfg), _vidx(vidx) { }
650
inline bool Value::hasValue() const { return _config && _vidx != detail::NULL_VALUE_INDEX; }
651
inline Value::operator detail::PseudoBool::Type () const { return this->hasValue() ? detail::PseudoBool::TRUE : detail::PseudoBool::FALSE; }
652
inline bool Value::operator ! () const { return ! this->hasValue(); }
653
inline ValueType Value::getType() const { return this->hasValue() ? _config._table[_vidx]._type : VoidValue; }
654
inline ConstBuffer const& Value::getText() const {
655
return this->hasValue() ? _config._table[_vidx]._text : detail::NULL_CONST_BUFFER;
657
inline Value& Value::setText(ConstBuffer const& text) {
658
detail::ValueItem* item = this->item();
659
if (item) item->_text = text;
662
inline ConstBuffer const& Value::getName() const {
663
detail::ValueItem const* item = this->item();
664
return item ? item->_name : detail::NULL_CONST_BUFFER;
666
inline size_t Value::getIndex() const {
667
detail::ValueItem const* item = this->item();
668
return item ? item->_local_index : 0;
671
inline bool Value::isLiteral() const { return 0 != (detail::IS_LITERAL & detail::Type_Property[this->getType()]); }
672
inline bool Value::isContainer() const { return 0 != (detail::IS_CONTAINER & detail::Type_Property[this->getType()]); }
673
inline Value Value::getParent() const { return this->hasValue() ? Value(_config, _config._table[_vidx]._parent) : Value(); }
674
inline bool Value::isRoot() const { return this->hasValue() && _vidx == 0; }
675
inline Value& Value::reset() { _config = Configuration(); _vidx = detail::NULL_VALUE_INDEX; return *this; }
676
inline detail::ValueItem* Value::item() { return this->hasValue() ? &(_config._table[_vidx]) : 0; }
677
inline detail::ValueItem const* Value::item() const { return const_cast<self*>(this)->item(); }
678
inline Value Value::operator [] (char const* name) const { return (*this)[ConstBuffer(name, strlen(name))]; }
679
inline size_t Value::childCount() const {
680
detail::ValueItem const* item = this->item();
681
return item ? item->_children.size() : 0;
683
inline Value Value::find(char const* path) { return this->find(ConstBuffer(path, strlen(path))); }
684
inline int Value::getSourceLine() const {
685
detail::ValueItem const* item = this->item();
686
return item ? item->_srcLine : 0;
688
inline int Value::getSourceColumn() const {
689
detail::ValueItem const* item = this->item();
690
return item ? item->_srcColumn : 0;
692
inline Value& Value::setSourceLine(int line) {
693
detail::ValueItem* item = this->item();
694
if (item) item->_srcLine = line;
697
inline Value& Value::setSourceColumn(int col) {
698
detail::ValueItem* item = this->item();
699
if (item) item->_srcColumn = col;
702
inline Value& Value::setSource(int line, int col) {
703
detail::ValueItem* item = this->item();
705
item->_srcLine = line;
706
item->_srcColumn = col;
711
inline Path::ImplType::ImplType() { }
713
inline Path::Path() { }
714
inline Path::ImplType* Path::instance() { if (!_ptr) _ptr = new ImplType; return _ptr.get(); }
715
inline Path& Path::append(ConstBuffer const& tag) { this->instance()->_elements.push_back(tag); return *this; }
716
inline Path& Path::append(size_t index) { this->instance()->_elements.push_back(ConstBuffer(0, index)); return *this; }
717
inline size_t Path::count() const { return _ptr ? _ptr->_elements.size() : 0; }
718
inline ConstBuffer const& Path::operator [] (size_t idx) const { return _ptr ? _ptr->_elements[idx] : detail::NULL_CONST_BUFFER; }
720
inline Path::Parser::Parser() : _input(0,0), _c(0) { }
721
inline Path::Parser::Parser( ConstBuffer const& text ) : _input(text), _c(text._ptr) { }
722
inline bool Path::Parser::hasInput() const { return _input._ptr && _input._ptr + _input._size > _c; }
724
inline bool Configuration::operator ! () const { return ! _table; }
725
inline Configuration::operator detail::PseudoBool::Type() const { return _table.operator detail::PseudoBool::Type(); }
726
inline Value Configuration::find( char const* path ) { return this->getRoot().find(path); }
727
inline Buffer Configuration::alloc(size_t n) { return _table.alloc(n); }
728
inline size_t Configuration::childCount() const { return this->getRoot().childCount(); }
729
inline Value Configuration::operator [] (size_t idx) const { return (this->getRoot())[idx]; }
730
inline Value Configuration::operator [] ( ConstBuffer const& name ) const { return (this->getRoot())[name]; }
731
inline Value Configuration::operator [] ( char const* name ) const { return (this->getRoot())[name]; }
733
}} // namespace ts::config