mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-03-16 14:05:28 +00:00
restructured repository based on following standards:
https://github.com/HW-Core/directory-structure
This commit is contained in:
760
modules/dep/g3dlite/include/G3D/Any.h
Normal file
760
modules/dep/g3dlite/include/G3D/Any.h
Normal file
@@ -0,0 +1,760 @@
|
||||
/**
|
||||
@file Any.h
|
||||
|
||||
@author Morgan McGuire, Shawn Yarbrough, and Corey Taylor
|
||||
@maintainer Morgan McGuire
|
||||
|
||||
@created 2006-06-11
|
||||
@edited 2010-03-16
|
||||
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef G3D_Any_h
|
||||
#define G3D_Any_h
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Table.h"
|
||||
#include "G3D/Array.h"
|
||||
#include "G3D/Set.h"
|
||||
#include "G3D/AtomicInt32.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include <string>
|
||||
|
||||
// needed for Token
|
||||
#include "G3D/TextInput.h"
|
||||
|
||||
#ifdef verify
|
||||
#undef verify
|
||||
#endif
|
||||
|
||||
namespace G3D {
|
||||
|
||||
class TextOutput;
|
||||
|
||||
/**
|
||||
\brief Easy loading and saving of human-readable configuration files.
|
||||
|
||||
Any encodes typed, structured data and can serialize it to a human
|
||||
readable format that is very similar to the Python language's data
|
||||
syntax. It is well-suited for quickly creating human-readable file
|
||||
formats, especially since deserialization and serialization preserve
|
||||
comments and an Any can tell you what file and line it came from. The
|
||||
syntax allows most C++ editors to properly highlight Any files, and
|
||||
makes it easy to design little ad-hoc C-like languages in
|
||||
configuration files.
|
||||
|
||||
The class is designed so that copying Anys generally is fast, even if
|
||||
it is a large array or table. This is because data is shared between
|
||||
copies until it is mutated, at which point an actual copy occurs.
|
||||
|
||||
\section Example
|
||||
Sample File:
|
||||
<pre>
|
||||
{
|
||||
shape = "round",
|
||||
|
||||
// in meters
|
||||
radius = 3.7,
|
||||
|
||||
position = Vector3(1.0, -1.0, 0.0),
|
||||
video = { format = "RGB8", size = (320, 200)},
|
||||
|
||||
material = #include("rocks.mat")
|
||||
}
|
||||
</pre>
|
||||
|
||||
Sample code using Any:
|
||||
<pre>
|
||||
Any x;
|
||||
x.load("ball.txt");
|
||||
if (x["shape"].string() == "round") {
|
||||
x["density"] = 3;
|
||||
}
|
||||
x.save("ball.txt");
|
||||
</pre>
|
||||
|
||||
The custom serialization format was chosen to be terse, easy for
|
||||
humans to read, and easy for machines to parse. It was specifically
|
||||
chosen over formats like XML, YAML, JSON, S-expressions, and Protocol
|
||||
Buffers, although there is no reason you could not write readers and
|
||||
writers for G3D::Any that support those.
|
||||
|
||||
G3D::Any assumes that structures do not contain cycles; it is an
|
||||
error to create a structure like:
|
||||
|
||||
<pre>
|
||||
Any x(Any::ARRAY);
|
||||
x.array().append(x); // don't do this!
|
||||
</pre>
|
||||
|
||||
although no exception will be thrown at runtime during that append.
|
||||
|
||||
|
||||
\section Parsing
|
||||
|
||||
The primary use of Any is to create your own text file formats.
|
||||
The Vector3 constructor is a good example of how to use the Any::verify
|
||||
methods to provide good error checking while parsing such formats:
|
||||
|
||||
<pre>
|
||||
Vector3::Vector3(const Any& any) {
|
||||
any.verifyName("Vector3");
|
||||
any.verifyType(Any::TABLE, Any::ARRAY);
|
||||
any.verifySize(3);
|
||||
|
||||
if (any.type() == Any::ARRAY) {
|
||||
x = any[0];
|
||||
y = any[1];
|
||||
z = any[2];
|
||||
} else {
|
||||
// Table
|
||||
x = any["x"];
|
||||
y = any["y"];
|
||||
z = any["z"];
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
It is often convenient to iterate through the table portion:
|
||||
|
||||
<pre>
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& k = toLower(it->key);
|
||||
if (key == "hello") {
|
||||
...
|
||||
} else if (key == "goodbye") {
|
||||
...
|
||||
} else {
|
||||
any.verify(false, "Unsupported key: " + it->key);
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
\section BNF
|
||||
Serialized format BNF:
|
||||
|
||||
<pre>
|
||||
identifier ::= (letter | "_") (letter | digit | "_")*
|
||||
identifier-op ::= "::" | "->" | "."
|
||||
|
||||
identifier-exp ::= [identifier-op] identifier (identifier-op identifier)*
|
||||
|
||||
comment ::= C++ single or multi-line comments
|
||||
separator ::= "," | ";"
|
||||
|
||||
number ::= <legal C printf number format>
|
||||
string ::= <legal C double-quoted string; backslashes must be escaped>
|
||||
boolean ::= "True" | "False"
|
||||
none ::= "None"
|
||||
array ::= ("(" | "[") [ value (separator value)* [separator] ] (")" | "]")
|
||||
pair ::= (identifier | string) "=" value
|
||||
table ::= "{" [ pair (separator pair)* [separator] ] "}"
|
||||
named-array ::= identifier-exp array
|
||||
named-table ::= identifier-exp table
|
||||
include ::= "#" "include" "(" string ")"
|
||||
|
||||
value ::= [comment] (none | number | boolean | string | array | table | named-array | named-table | include)
|
||||
</pre>
|
||||
|
||||
Except for single-line comments, whitespace is not significant.
|
||||
All parsing is case-insensitive.
|
||||
|
||||
The include expression pastes the contents of the named file in as if
|
||||
they appeared in the original source. Note that an include expression
|
||||
can only appear in the locations where a value is expected. This means
|
||||
that it cannot yield more than one element of an array and cannot serve
|
||||
as the pair in a table.
|
||||
|
||||
The deserializer allows the substitution of [] for () when writing
|
||||
tuples and ";" for ",". These are convenient when mimicing a
|
||||
programming language, e.g., <code>"[ printf("hello world."); clearScreen();]"</code>
|
||||
parses as an array containing two named arrays within it. The
|
||||
deserializer also allows a trailing comma inside any array or table,
|
||||
which also convenient when commenting out the last element.
|
||||
|
||||
The serializer indents four spaces for each level of nesting.
|
||||
Tables are written with the keys in alphabetic order.
|
||||
*/
|
||||
class Any {
|
||||
public:
|
||||
|
||||
enum Type {NONE, BOOLEAN, NUMBER, STRING, ARRAY, TABLE};
|
||||
|
||||
static std::string toString(Type t);
|
||||
|
||||
/** Where an Any came from in a file. Useful for throwing parsing errors */
|
||||
class Source {
|
||||
public:
|
||||
std::string filename;
|
||||
int line;
|
||||
int character;
|
||||
|
||||
Source() : line(0), character(0) {}
|
||||
|
||||
void set(const TextInput& ti, const Token& t) {
|
||||
filename = ti.filename();
|
||||
line = t.line();
|
||||
character = t.character();
|
||||
}
|
||||
};
|
||||
|
||||
typedef Array<Any> AnyArray;
|
||||
typedef Table<std::string, Any> AnyTable;
|
||||
|
||||
private:
|
||||
|
||||
/** Called from deserialize() */
|
||||
static void deserializeComment(TextInput& ti, Token& token, std::string& comment);
|
||||
|
||||
/** NONE, BOOLEAN, and NUMBER are stored directly in the Any */
|
||||
union SimpleValue {
|
||||
bool b;
|
||||
double n;
|
||||
|
||||
inline SimpleValue() : n(0.0) {}
|
||||
inline SimpleValue(bool x) : b(x) {}
|
||||
inline SimpleValue(double x) : n(x) {}
|
||||
};
|
||||
|
||||
class Data {
|
||||
public:
|
||||
/** ARRAY, TABLE, or STRING value only. NULL otherwise. */
|
||||
union Value {
|
||||
std::string* s;
|
||||
Array<Any>* a;
|
||||
AnyTable* t;
|
||||
inline Value() : s(NULL) {}
|
||||
};
|
||||
|
||||
// Needed so that the destructor knows what is in Value
|
||||
// and can call its destructor.
|
||||
Type type;
|
||||
|
||||
/** Always points to memory that is allocated with the Data, so
|
||||
the destructor does not delete this. */
|
||||
Value value;
|
||||
|
||||
std::string comment;
|
||||
|
||||
std::string name;
|
||||
|
||||
/** For STRING, ARRAY and TABLE types, m_value is shared between
|
||||
multiple instances. Mutation is allowed only if the reference
|
||||
count is exactly 1, otherwise the mutating instance must copy
|
||||
the value. This is not used for other types.
|
||||
*/
|
||||
AtomicInt32 referenceCount;
|
||||
|
||||
Source source;
|
||||
|
||||
private:
|
||||
|
||||
/** Called by create() */
|
||||
inline Data(Type t) : type(t), referenceCount(1) {}
|
||||
|
||||
/** Called by destroy */
|
||||
~Data();
|
||||
|
||||
public:
|
||||
|
||||
/** Clones the argument */
|
||||
static Data* create(const Data* d);
|
||||
static Data* create(Type t);
|
||||
|
||||
/** Free d, invoking its destructor and freeing the memory for
|
||||
the value. */
|
||||
static void destroy(Data* d);
|
||||
|
||||
};
|
||||
|
||||
/** If not empty, this Any was created from operator[] on a table
|
||||
and perhaps was not intended to exist. The name is needed to
|
||||
format the error message if it is read from before it is
|
||||
written to.
|
||||
|
||||
The source of a placeholder object is that of the parent
|
||||
object until it is written.
|
||||
*/
|
||||
std::string m_placeholderName;
|
||||
|
||||
Type m_type;
|
||||
SimpleValue m_simpleValue;
|
||||
mutable Data* m_data;
|
||||
|
||||
/** Called before every read operation to ensure that this object
|
||||
is not a placeholder. */
|
||||
void beforeRead() const;
|
||||
|
||||
/** Called before every write operation to wipe the placeholder
|
||||
status. */
|
||||
void beforeWrite();
|
||||
|
||||
/** Decrements the reference count (if there is one). If the
|
||||
reference count is zero after decrement, calls delete on @a m_data
|
||||
and sets it to NULL.
|
||||
*/
|
||||
void dropReference();
|
||||
|
||||
/** Allocate the Data object if it does not exist */
|
||||
void ensureData();
|
||||
|
||||
/** If m_data is not NULL, ensure that it has a unique reference
|
||||
and contains a valid m_data. This has a race condition if two
|
||||
threads are both trying to modify the same Any
|
||||
simultaneously.*/
|
||||
void ensureMutable();
|
||||
|
||||
/** Read an unnamed a TABLE or ARRAY. Token should be the open
|
||||
paren token; it is the next token after the close on
|
||||
return. Called from deserialize().*/
|
||||
void deserializeBody(TextInput& ti, Token& token);
|
||||
|
||||
void deserialize(TextInput& ti, Token& token);
|
||||
|
||||
/** Read the name of a named Array or Table. */
|
||||
static void deserializeName(TextInput& ti, Token& token, std::string& name);
|
||||
|
||||
/** Read until a comma is consumed or a close paren is hit, and
|
||||
return that token. Considers the passed in token to be the first
|
||||
value read. */
|
||||
static void readUntilCommaOrClose(TextInput& ti, Token& token);
|
||||
|
||||
/** Construct an Any that is a proxy for a table fetch from \a data.
|
||||
This proxy can be copied exactly once on return from operator[].*/
|
||||
Any(const std::string& key, Data* data);
|
||||
|
||||
inline bool isPlaceholder() const {
|
||||
return ! m_placeholderName.empty();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/** Base class for all Any exceptions.*/
|
||||
class Exception {
|
||||
public:
|
||||
virtual ~Exception() {}
|
||||
};
|
||||
|
||||
/** Thrown by operator[] when a key is not present in a const table. */
|
||||
class KeyNotFound : public ParseError {
|
||||
public:
|
||||
std::string key;
|
||||
};
|
||||
|
||||
/** Thrown by operator[] when an array index is not present. */
|
||||
class IndexOutOfBounds : public Exception {
|
||||
public:
|
||||
int index;
|
||||
int size;
|
||||
inline IndexOutOfBounds() : index(0), size(0) {}
|
||||
inline IndexOutOfBounds(int i, int s) : index(i), size(s) {}
|
||||
};
|
||||
|
||||
/** NONE constructor */
|
||||
Any();
|
||||
|
||||
/** Deserialize */
|
||||
explicit Any(TextInput& t);
|
||||
|
||||
Any(const Any& x);
|
||||
|
||||
/** NUMBER constructor */
|
||||
Any(double x);
|
||||
|
||||
#ifdef G3D_32BIT
|
||||
/** NUMBER constructor */
|
||||
Any(int64 x);
|
||||
#endif // G3D_32BIT
|
||||
|
||||
#if 0
|
||||
/** NUMBER constructor */
|
||||
Any(int32 x);
|
||||
#endif // 0
|
||||
|
||||
/** NUMBER constructor */
|
||||
Any(long x);
|
||||
|
||||
/** NUMBER constructor */
|
||||
Any(int x);
|
||||
|
||||
/** NUMBER constructor */
|
||||
Any(short x);
|
||||
|
||||
/** BOOLEAN constructor */
|
||||
Any(bool x);
|
||||
|
||||
/** STRING constructor */
|
||||
Any(const std::string& x);
|
||||
|
||||
/** STRING constructor */
|
||||
Any(const char* x);
|
||||
|
||||
/** \a t must be ARRAY or TABLE */
|
||||
Any(Type t, const std::string& name = "");
|
||||
|
||||
~Any();
|
||||
|
||||
/** Removes the comment and name */
|
||||
Any& operator=(const Any& x);
|
||||
|
||||
/** Removes the comment and name */
|
||||
Any& operator=(double x);
|
||||
|
||||
/** Removes the comment and name */
|
||||
Any& operator=(int x);
|
||||
|
||||
/** Removes the comment and name */
|
||||
Any& operator=(bool x);
|
||||
|
||||
/** Removes the comment and name */
|
||||
Any& operator=(const std::string& x);
|
||||
|
||||
/** Removes the comment and name */
|
||||
Any& operator=(const char* x);
|
||||
|
||||
/** \a t must be ARRAY, TABLE, or NONE. Removes the comment and name */
|
||||
Any& operator=(Type t);
|
||||
|
||||
Type type() const;
|
||||
|
||||
/** Same as deserialize or load, but operates on a string instead
|
||||
of a stream or file.
|
||||
|
||||
\sa deserialize, load
|
||||
*/
|
||||
void parse(const std::string& src);
|
||||
|
||||
std::string unparse() const;
|
||||
|
||||
/** Comments appear before values when they are in serialized form.*/
|
||||
const std::string& comment() const;
|
||||
void setComment(const std::string& c);
|
||||
|
||||
/** True if this is the NONE value */
|
||||
bool isNone() const;
|
||||
|
||||
/** Throws a ParseError exception if this is not a number */
|
||||
double number() const;
|
||||
const std::string& string() const;
|
||||
bool boolean() const;
|
||||
|
||||
/** If a valid string, takes the string value and creates a fully qualified filename.
|
||||
If not found, the returned string is empty.
|
||||
|
||||
The file is searched for the following ways:
|
||||
|
||||
- In the directory from which the Any was loaded.
|
||||
- By calling System::findDataFile as you would with other data files.
|
||||
*/
|
||||
std::string resolveStringAsFilename() const;
|
||||
|
||||
/** If this is named ARRAY or TABLE, returns the name. */
|
||||
const std::string& name() const;
|
||||
|
||||
/** If this is named ARRAY or TABLE, returns true if the name begins with \a s. The comparision is case insensitive. */
|
||||
bool nameBeginsWith(const std::string& s) const;
|
||||
|
||||
/** If this is named ARRAY or TABLE, returns true if the name begins with \a s. The comparision is case insensitive. */
|
||||
bool nameBeginsWith(const char* s) const;
|
||||
|
||||
/** If this is named ARRAY or TABLE, returns true if the name is \a s. The comparision is case insensitive. */
|
||||
bool nameEquals(const std::string& s) const;
|
||||
|
||||
/** If this is named ARRAY or TABLE, returns true if the name is\a s. The comparision is case insensitive. */
|
||||
bool nameEquals(const char* s) const;
|
||||
|
||||
/** \brief Set the name used when serializing an ARRAY or TABLE.
|
||||
|
||||
Only legal for ARRAY or TABLE. The \a name must begin with a letter
|
||||
and contain only letters, numbers, underscores and scope operators.
|
||||
|
||||
<pre>
|
||||
a2z
|
||||
hello
|
||||
Foo::bar
|
||||
color.red
|
||||
this->that
|
||||
__x
|
||||
</pre>
|
||||
|
||||
|
||||
The scope operators "::", "->", and
|
||||
".", may have spaces around them. The name may not
|
||||
contain parentheses.
|
||||
*/
|
||||
void setName(const std::string& name);
|
||||
|
||||
/** Number of elements if this is an ARRAY or TABLE */
|
||||
int size() const;
|
||||
int length() const;
|
||||
|
||||
/** For an array, returns the ith element */
|
||||
const Any& operator[](int i) const;
|
||||
Any& operator[](int i);
|
||||
|
||||
const Any& last() const {
|
||||
return (*this)[size() - 1];
|
||||
}
|
||||
|
||||
Any& last() {
|
||||
return (*this)[size() - 1];
|
||||
}
|
||||
|
||||
/** Directly exposes the underlying data structure for an ARRAY. */
|
||||
const Array<Any>& array() const;
|
||||
void append(const Any& v0);
|
||||
void append(const Any& v0, const Any& v1);
|
||||
void append(const Any& v0, const Any& v1, const Any& v2);
|
||||
void append(const Any& v0, const Any& v1, const Any& v2, const Any& v3);
|
||||
|
||||
/** Directly exposes the underlying data structure for table.*/
|
||||
const Table<std::string, Any>& table() const;
|
||||
|
||||
/** For a table, returns the element for \a key. Throws KeyNotFound
|
||||
exception if the element does not exist.
|
||||
*/
|
||||
const Any& operator[](const std::string& key) const;
|
||||
|
||||
// Needed to prevent the operator[](int) overload from catching
|
||||
// string literals
|
||||
const Any& operator[](const char* key) const {
|
||||
return operator[](std::string(key));
|
||||
}
|
||||
|
||||
/**
|
||||
Fetch an element from a table. This can be used as:
|
||||
|
||||
<pre>
|
||||
a["key"] = value; (create the key if it did not exist)
|
||||
</pre>
|
||||
|
||||
or
|
||||
|
||||
<pre>
|
||||
value = a["key"]; (throw an error if the key did not exist)
|
||||
</pre>
|
||||
|
||||
<b>Note:</b>
|
||||
In order to cause elements to be correctly created in the
|
||||
first case while still providing "key not found" errors in the
|
||||
second case, the Any returned is a special object that delays
|
||||
the actual fetch until the following assignment or method
|
||||
call. This means that in the event of an error, the exception
|
||||
may be thrown from a line other than the actual fetch. Use
|
||||
the Any::get() or the const Any::operator[]() methods to avoid
|
||||
this behavior and ensure error-checking at fetch time.
|
||||
*/
|
||||
Any& operator[](const std::string& key);
|
||||
|
||||
/** \copydoc Any::operator[](const std::string&) */
|
||||
Any& operator[](const char* key) {
|
||||
return operator[](std::string(key));
|
||||
}
|
||||
|
||||
/** For a table, returns the element for key \a x and \a
|
||||
defaultVal if it does not exist. */
|
||||
const Any& get(const std::string& key, const Any& defaultVal) const;
|
||||
|
||||
/** Returns true if this key is in the TABLE. Illegal to call on an object that is not a TABLE. */
|
||||
bool containsKey(const std::string& key) const;
|
||||
|
||||
/** For a table, assigns the element for key k. */
|
||||
void set(const std::string& key, const Any& val);
|
||||
|
||||
/** for an ARRAY, resizes and returns the last element */
|
||||
Any& next();
|
||||
|
||||
/** The parent directory of the location from which this Any was loaded. This is useful for
|
||||
interpreting filenames relative to the Any's source location,
|
||||
which may not match the current directory if the Any was from an included file. */
|
||||
std::string sourceDirectory() const;
|
||||
|
||||
/** True if the Anys are exactly equal, ignoring comments. Applies deeply on arrays and tables. */
|
||||
bool operator==(const Any& x) const;
|
||||
bool operator!=(const Any& x) const;
|
||||
|
||||
operator int() const;
|
||||
operator float() const;
|
||||
operator double() const;
|
||||
operator bool() const;
|
||||
operator std::string() const;
|
||||
|
||||
/** Resize to \a n elements, where new elements are NIL
|
||||
It is an error to call this method if this is not an Any::ARRAY */
|
||||
void resize(int n);
|
||||
|
||||
/**
|
||||
Clears all entries.
|
||||
This must be a TABLE or ARRAY */
|
||||
void clear();
|
||||
|
||||
/** Parse from a file.
|
||||
\sa deserialize, parse */
|
||||
void load(const std::string& filename);
|
||||
|
||||
/** Uses the serialize method. */
|
||||
void save(const std::string& filename) const;
|
||||
|
||||
void serialize(TextOutput& to) const;
|
||||
/** Parse from a stream.
|
||||
\sa load, parse */
|
||||
void deserialize(TextInput& ti);
|
||||
|
||||
const Source& source() const;
|
||||
|
||||
/** Throws a ParseError if \a value is false. Useful for quickly
|
||||
creating parse rules in classes that deserialize from Any.
|
||||
*/
|
||||
void verify(bool value, const std::string& message = "") const;
|
||||
|
||||
|
||||
/** Verifies that the name <i>begins with</i> identifier \a n (case insensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyName(const std::string& n) const;
|
||||
|
||||
/** Verifies that the name <i>begins with</i> identifier \a n or \a m (case insensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyName(const std::string& n, const std::string& m) const;
|
||||
|
||||
/** Verifies that the type is \a t. */
|
||||
void verifyType(Type t) const;
|
||||
|
||||
/** Throws an exception if the type is not \a t0 or \a t1. */
|
||||
void verifyType(Type t0, Type t1) const;
|
||||
|
||||
/** Verifies that the size is between \a low and \a high, inclusive */
|
||||
void verifySize(int low, int high) const;
|
||||
|
||||
/** Verifies that the size is exactly \a s */
|
||||
void verifySize(int s) const;
|
||||
|
||||
private:
|
||||
|
||||
void deserializeTable(TextInput& ti);
|
||||
void deserializeArray(TextInput& ti,const std::string& term);
|
||||
|
||||
}; // class Any
|
||||
|
||||
|
||||
/**
|
||||
Convenient iteration over the keys of a Any::TABLE, usually
|
||||
for implementing construction of an object from an Any.
|
||||
|
||||
Getting an element using either iteration or explicit requests
|
||||
consumes that element from the iterator (but not from the Any!)
|
||||
It is an error to consume the same element more than once from
|
||||
the same iterator.
|
||||
|
||||
<pre>
|
||||
AnyKeyIterator r(a);
|
||||
r.getIfPresent("enabled", enabled);
|
||||
r.getIfPresent("showSamples", showSamples);
|
||||
r.getIfPresent("showTiles", showTiles);
|
||||
|
||||
r.verifyDone();
|
||||
</pre>
|
||||
|
||||
\beta
|
||||
*/
|
||||
class AnyTableReader {
|
||||
private:
|
||||
Any m_any;
|
||||
Set<std::string> m_alreadyRead;
|
||||
public:
|
||||
|
||||
/** Verifies that \a is a TABLE with the given \a name. */
|
||||
AnyTableReader(const std::string& name, const Any& a) : m_any(a) {
|
||||
try {
|
||||
m_any.verifyType(Any::TABLE);
|
||||
m_any.verifyName(name);
|
||||
} catch (const ParseError& e) {
|
||||
// If an exception is thrown, the destructors will not be
|
||||
// invoked automatically.
|
||||
m_any.~Any();
|
||||
m_alreadyRead.~Set();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/** Verifies that \a is a TABLE. */
|
||||
AnyTableReader(const Any& a) : m_any(a) {
|
||||
try {
|
||||
m_any.verifyType(Any::TABLE);
|
||||
} catch (const ParseError& e) {
|
||||
// If an exception is thrown, the destructors will not be
|
||||
// invoked automatically.
|
||||
m_any.~Any();
|
||||
m_alreadyRead.~Set();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasMore() const {
|
||||
return m_any.size() > m_alreadyRead.size();
|
||||
}
|
||||
|
||||
/** Verifies that all keys have been read. */
|
||||
void verifyDone() const {
|
||||
if (hasMore()) {
|
||||
// Generate all keys
|
||||
// Remove the ones we've read
|
||||
// Assert the rest
|
||||
// any.verify("");
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/** Returns the current key */
|
||||
const std::string& key() const;
|
||||
|
||||
/** Returns the current value */
|
||||
const Any& value() const;
|
||||
|
||||
AnyKeyIterator& operator++();
|
||||
#endif
|
||||
|
||||
/** If key \s appears in the any, reads its value into \a v and
|
||||
removes that key from the ones available to iterate over.
|
||||
|
||||
If key \s does not appear in the any, throws a G3D::ParseError.
|
||||
|
||||
Assumes that if key \s appears in the any it has not already been extracted
|
||||
by this iterator. If it has been read before, an assertion will fail in debug mode.
|
||||
|
||||
*/
|
||||
template<class ValueType>
|
||||
void get(const std::string& s, ValueType& v) {
|
||||
v = m_any[s];
|
||||
m_alreadyRead.insert(toLower(s));
|
||||
}
|
||||
|
||||
/** Get the value associated with a key only if the key is actually present.
|
||||
|
||||
If key \s appears in the any, reads its value into \a v and
|
||||
removes that key from the ones available to iterate over.
|
||||
|
||||
If key \s does not appear in the any, does nothing.
|
||||
|
||||
Assumes that if key \s appears in the any it has not already been extracted
|
||||
by this iterator. If it has been read before, an assertion will fail in debug mode.
|
||||
|
||||
\return True if the value was read.
|
||||
*/
|
||||
template<class ValueType>
|
||||
bool getIfPresent(const std::string& s, ValueType& v) {
|
||||
if (m_any.containsKey(s)) {
|
||||
debugAssertM(! m_alreadyRead.contains(toLower(s)), "read twice");
|
||||
|
||||
get(s, v);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace G3D
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user