Core/Misc: update g3dlite lib (#2904)
* Core/Misc: update g3dlite lib * update Co-authored-by: Francesco Borzì <borzifrancesco@gmail.com>
This commit is contained in:
Vendored
+419
-155
@@ -1,13 +1,13 @@
|
||||
/**
|
||||
@file Any.h
|
||||
\file Any.h
|
||||
|
||||
@author Morgan McGuire, Shawn Yarbrough, and Corey Taylor
|
||||
@maintainer Morgan McGuire
|
||||
\author Morgan McGuire, Shawn Yarbrough, and Corey Taylor
|
||||
\maintainer Morgan McGuire
|
||||
|
||||
@created 2006-06-11
|
||||
@edited 2010-03-16
|
||||
\created 2006-06-11
|
||||
\edited 2013-03-29
|
||||
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
Copyright 2000-2013, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
#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"
|
||||
#include "G3D/TextOutput.h"
|
||||
|
||||
#ifdef verify
|
||||
#undef verify
|
||||
@@ -38,7 +38,8 @@ class TextOutput;
|
||||
|
||||
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
|
||||
syntax, and fully supports Python's data syntax as well.
|
||||
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
|
||||
@@ -61,7 +62,7 @@ Sample File:
|
||||
position = Vector3(1.0, -1.0, 0.0),
|
||||
video = { format = "RGB8", size = (320, 200)},
|
||||
|
||||
material = #include("rocks.mat")
|
||||
material = \#include("rocks.mat")
|
||||
}
|
||||
</pre>
|
||||
|
||||
@@ -79,7 +80,8 @@ 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.
|
||||
writers for G3D::Any that support those. Any also currently supports
|
||||
the JSON format.
|
||||
|
||||
G3D::Any assumes that structures do not contain cycles; it is an
|
||||
error to create a structure like:
|
||||
@@ -91,6 +93,17 @@ x.array().append(x); // don't do this!
|
||||
|
||||
although no exception will be thrown at runtime during that append.
|
||||
|
||||
\section includes
|
||||
|
||||
When parsing an Any from a file, the syntax
|
||||
<code>\#include(<i>filename</i>)</code> allows subsitution of the contents of
|
||||
<i>filename</i> for any single expression in an Any. The filename is interpreted
|
||||
relative to the file being parsed, and inside of the included file, relative filenames
|
||||
are interpreted with respect to the included file (and so on, recursively for nested
|
||||
inclusion).
|
||||
|
||||
Filenames are resolved with System::resolve and then System::findDataFile if not found,
|
||||
so they may contain environment variables.
|
||||
|
||||
\section Parsing
|
||||
|
||||
@@ -117,24 +130,12 @@ Vector3::Vector3(const Any& any) {
|
||||
}
|
||||
</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>
|
||||
It is often convenient to iterate through the table portion using G3D::AnyTableReader.
|
||||
|
||||
\section BNF
|
||||
Serialized format BNF:
|
||||
|
||||
\htmlonly
|
||||
<pre>
|
||||
identifier ::= (letter | "_") (letter | digit | "_")*
|
||||
identifier-op ::= "::" | "->" | "."
|
||||
@@ -145,18 +146,19 @@ comment ::= C++ single or multi-line comments
|
||||
separator ::= "," | ";"
|
||||
|
||||
number ::= <legal C printf number format>
|
||||
string ::= <legal C double-quoted string; backslashes must be escaped>
|
||||
string ::= <legal C double-quoted or unquoted string; backslashes must be escaped>
|
||||
boolean ::= "True" | "False"
|
||||
none ::= "None"
|
||||
array ::= ("(" | "[") [ value (separator value)* [separator] ] (")" | "]")
|
||||
pair ::= (identifier | string) "=" value
|
||||
table ::= "{" [ pair (separator pair)* [separator] ] "}"
|
||||
nil ::= "Nil" <not case sensitive> | "None" <case sensitive>
|
||||
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)
|
||||
value ::= [comment] (nil | number | boolean | string | array | table | named-array | named-table | include)
|
||||
</pre>
|
||||
\endhtmlonly
|
||||
|
||||
Except for single-line comments, whitespace is not significant.
|
||||
All parsing is case-insensitive.
|
||||
@@ -167,7 +169,7 @@ 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
|
||||
The deserializer allows the substitution of [] or {} 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
|
||||
@@ -176,11 +178,13 @@ 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.
|
||||
|
||||
\sa G3D::AnyTableReader
|
||||
*/
|
||||
class Any {
|
||||
public:
|
||||
|
||||
enum Type {NONE, BOOLEAN, NUMBER, STRING, ARRAY, TABLE};
|
||||
enum Type {NIL, BOOLEAN, NUMBER, STRING, ARRAY, TABLE, EMPTY_CONTAINER};
|
||||
|
||||
static std::string toString(Type t);
|
||||
|
||||
@@ -208,7 +212,7 @@ private:
|
||||
/** Called from deserialize() */
|
||||
static void deserializeComment(TextInput& ti, Token& token, std::string& comment);
|
||||
|
||||
/** NONE, BOOLEAN, and NUMBER are stored directly in the Any */
|
||||
/** NIL, BOOLEAN, and NUMBER are stored directly in the Any */
|
||||
union SimpleValue {
|
||||
bool b;
|
||||
double n;
|
||||
@@ -218,6 +222,11 @@ private:
|
||||
inline SimpleValue(double x) : n(x) {}
|
||||
};
|
||||
|
||||
/** The three options for Data::bracket */
|
||||
static const char* PAREN;
|
||||
static const char* BRACKET;
|
||||
static const char* BRACE;
|
||||
|
||||
class Data {
|
||||
public:
|
||||
/** ARRAY, TABLE, or STRING value only. NULL otherwise. */
|
||||
@@ -240,6 +249,16 @@ private:
|
||||
|
||||
std::string name;
|
||||
|
||||
/** If this Any was created by parsing an #include expression and
|
||||
has not been modified since, this is the original comment and
|
||||
include statement, as
|
||||
it originally appeared in the file (e.g., it may contain a relative
|
||||
filename). If this is non-empty, then when serialized, this
|
||||
Any will turn into an #include expression instead of unparsing
|
||||
its contents of the any.
|
||||
*/
|
||||
std::string includeLine;
|
||||
|
||||
/** 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
|
||||
@@ -249,10 +268,16 @@ private:
|
||||
|
||||
Source source;
|
||||
|
||||
/** Two-character string of "{}", "[]", or "()"; to be used when unparsing. */
|
||||
const char* bracket;
|
||||
|
||||
/** ';' or ',' separator to be used when unparsing */
|
||||
char separator;
|
||||
|
||||
private:
|
||||
|
||||
/** Called by create() */
|
||||
inline Data(Type t) : type(t), referenceCount(1) {}
|
||||
inline Data(Type t, const char* b, char s) : type(t), referenceCount(1), bracket(b), separator(s) {}
|
||||
|
||||
/** Called by destroy */
|
||||
~Data();
|
||||
@@ -261,12 +286,11 @@ private:
|
||||
|
||||
/** Clones the argument */
|
||||
static Data* create(const Data* d);
|
||||
static Data* create(Type t);
|
||||
static Data* create(Type t, const char* b = NULL, char s = '\0');
|
||||
|
||||
/** 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
|
||||
@@ -283,12 +307,11 @@ private:
|
||||
SimpleValue m_simpleValue;
|
||||
mutable Data* m_data;
|
||||
|
||||
/** Called before every read operation to ensure that this object
|
||||
is not a placeholder. */
|
||||
/** Called before every read operation. */
|
||||
void beforeRead() const;
|
||||
|
||||
/** Called before every write operation to wipe the placeholder
|
||||
status. */
|
||||
/** Called before every write operation to this Any. Wipes the placeholder
|
||||
status and includedFrom entry. */
|
||||
void beforeWrite();
|
||||
|
||||
/** Decrements the reference count (if there is one). If the
|
||||
@@ -316,43 +339,61 @@ private:
|
||||
/** 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
|
||||
/** Read until a separator 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);
|
||||
static void readUntilSeparatorOrClose(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 {
|
||||
bool isPlaceholder() const {
|
||||
return ! m_placeholderName.empty();
|
||||
}
|
||||
|
||||
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);
|
||||
Any _get(const std::string& key, const Any& defaultVal) const;
|
||||
void _set(const std::string& key, const Any& val);
|
||||
|
||||
void _parse(const std::string& src);
|
||||
|
||||
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;
|
||||
|
||||
KeyNotFound(const Data* data) {
|
||||
if (data) {
|
||||
filename = data->source.filename;
|
||||
line = data->source.line;
|
||||
character = data->source.character;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Thrown by operator[] when an array index is not present. */
|
||||
class IndexOutOfBounds : public Exception {
|
||||
class IndexOutOfBounds : public ParseError {
|
||||
public:
|
||||
int index;
|
||||
int size;
|
||||
inline IndexOutOfBounds() : index(0), size(0) {}
|
||||
inline IndexOutOfBounds(int i, int s) : index(i), size(s) {}
|
||||
IndexOutOfBounds() : index(0), size(0) {}
|
||||
IndexOutOfBounds(const Data* data, int i, int s) : index(i), size(s) {
|
||||
if (data) {
|
||||
filename = data->source.filename;
|
||||
line = data->source.line;
|
||||
character = data->source.character;
|
||||
}
|
||||
message = format("Index out of bounds: index = %d, array size = %d", i, s);
|
||||
}
|
||||
};
|
||||
|
||||
/** NONE constructor */
|
||||
/** NIL constructor */
|
||||
Any();
|
||||
|
||||
/** Deserialize */
|
||||
@@ -361,108 +402,133 @@ public:
|
||||
Any(const Any& x);
|
||||
|
||||
/** NUMBER constructor */
|
||||
Any(double x);
|
||||
explicit Any(double x);
|
||||
|
||||
#ifdef G3D_32BIT
|
||||
/** NUMBER constructor */
|
||||
Any(int64 x);
|
||||
#endif // G3D_32BIT
|
||||
explicit Any(float x);
|
||||
|
||||
#if 0
|
||||
#if defined(G3D_32Bit) || defined(_MSC_VER)
|
||||
/** NUMBER constructor */
|
||||
Any(int32 x);
|
||||
#endif // 0
|
||||
explicit Any(int64 x) : m_type(NUMBER), m_simpleValue((double)x), m_data(NULL) {}
|
||||
#endif
|
||||
|
||||
/** NUMBER constructor */
|
||||
Any(long x);
|
||||
explicit Any(long x);
|
||||
|
||||
/** NUMBER constructor */
|
||||
Any(int x);
|
||||
explicit Any(int x);
|
||||
|
||||
/** NUMBER constructor */
|
||||
Any(short x);
|
||||
explicit Any(char x);
|
||||
|
||||
/** NUMBER constructor */
|
||||
explicit Any(short x);
|
||||
|
||||
/** BOOLEAN constructor */
|
||||
Any(bool x);
|
||||
explicit Any(bool x);
|
||||
|
||||
/** STRING constructor */
|
||||
Any(const std::string& x);
|
||||
explicit Any(const std::string& x);
|
||||
|
||||
/** STRING constructor */
|
||||
Any(const char* x);
|
||||
explicit Any(const char* x);
|
||||
|
||||
/** \a t must be ARRAY or TABLE
|
||||
\param brackets must be "" (defaults to {} for table, () for array), "[]", "()", or "{}"
|
||||
\param separator must be ';', ',', or '\0' (defaults to ',' for array and ';' for table)
|
||||
*/
|
||||
explicit Any(Type t, const std::string& name = "", const std::string& brackets = "", const char separator = '\0');
|
||||
|
||||
/** Extensible constructor: call the toAny() method of any class. */
|
||||
template<class T>
|
||||
explicit Any(const T& v) : m_type(NIL), m_data(NULL) {
|
||||
*this = v.toAny();
|
||||
}
|
||||
|
||||
/** \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 */
|
||||
/** \a t must be ARRAY, TABLE, or NIL. Removes the comment and name */
|
||||
Any& operator=(Type t);
|
||||
|
||||
/** Assigns from an array. Assumes that T can be converted to Any. Removes the comment and name */
|
||||
template<class T>
|
||||
Any& operator=(const Array<T>& array) {
|
||||
*this = Any::ARRAY;
|
||||
resize(array.size());
|
||||
for (int i = 0; i < array.size(); ++i) {
|
||||
this->operator [](i) = array[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Removes the comment and name */
|
||||
template<class T>
|
||||
Any& operator=(const T& v) {
|
||||
*this = Any(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Type type() const;
|
||||
|
||||
/** Same as deserialize or load, but operates on a string instead
|
||||
of a stream or file.
|
||||
|
||||
\sa deserialize, load
|
||||
\sa deserialize, load, unparse
|
||||
*/
|
||||
void parse(const std::string& src);
|
||||
static Any parse(const std::string& src);
|
||||
|
||||
std::string unparse() const;
|
||||
std::string unparse(const TextOutput::Settings& s = TextOutput::Settings()) const;
|
||||
|
||||
/** \param allowCoercion If false, throws an error if the Any uses features that are not
|
||||
supported by JSON such as named arrays. Otherwise, silently coerces to JSON. */
|
||||
std::string unparseJSON(const TextOutput::Settings& s = TextOutput::Settings(), bool allowCoercion = true) 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;
|
||||
/** True if this is the NIL value */
|
||||
bool isNil() const;
|
||||
|
||||
/** Throws a ParseError exception if this is not a number */
|
||||
double number() const;
|
||||
float floatValue() 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.
|
||||
/** If a valid string, takes the string value and creates a fully
|
||||
qualified filename.
|
||||
|
||||
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.
|
||||
|
||||
Strings that begin with '<' and end with '>' are treated as
|
||||
escape sequences and are returned unmodifed.
|
||||
*/
|
||||
std::string resolveStringAsFilename() const;
|
||||
std::string resolveStringAsFilename(bool errorIfNotFound = true) 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. */
|
||||
/** 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. */
|
||||
/** 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. */
|
||||
/** 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. */
|
||||
/** 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.
|
||||
@@ -504,12 +570,29 @@ public:
|
||||
|
||||
/** 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.*/
|
||||
template<class T0>
|
||||
void append(const T0& v0) {
|
||||
_append(Any(v0));
|
||||
}
|
||||
|
||||
template<class T0, class T1>
|
||||
void append(const T0& v0, const T1& v1) {
|
||||
_append(Any(v0), Any(v1));
|
||||
}
|
||||
|
||||
template<class T0, class T1, class T2>
|
||||
void append(const T0& v0, const T1& v1, const T2& v2) {
|
||||
_append(Any(v0), Any(v1), Any(v2));
|
||||
}
|
||||
|
||||
template<class T0, class T1, class T2, class T3>
|
||||
void append(const T0& v0, const T1& v1, const T2& v2, const T3& v3) {
|
||||
_append(Any(v0), Any(v1), Any(v2), Any(v3));
|
||||
}
|
||||
|
||||
/** Directly exposes the underlying data structure for table.
|
||||
\sa G3D::AnyTableReader*/
|
||||
const Table<std::string, Any>& table() const;
|
||||
|
||||
/** For a table, returns the element for \a key. Throws KeyNotFound
|
||||
@@ -549,19 +632,25 @@ public:
|
||||
Any& operator[](const std::string& key);
|
||||
|
||||
/** \copydoc Any::operator[](const std::string&) */
|
||||
Any& operator[](const char* key) {
|
||||
inline 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;
|
||||
template<class T>
|
||||
Any get(const std::string& key, const T& defaultVal) const {
|
||||
return _get(key, Any(defaultVal));
|
||||
}
|
||||
|
||||
/** 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);
|
||||
template<class T>
|
||||
void set(const std::string& key, const T& val) {
|
||||
_set(key, Any(val));
|
||||
}
|
||||
|
||||
/** for an ARRAY, resizes and returns the last element */
|
||||
Any& next();
|
||||
@@ -573,14 +662,64 @@ public:
|
||||
|
||||
/** True if the Anys are exactly equal, ignoring comments. Applies deeply on arrays and tables. */
|
||||
bool operator==(const Any& x) const;
|
||||
|
||||
bool operator==(const std::string& s) const {
|
||||
return *this == Any(s);
|
||||
}
|
||||
|
||||
bool operator==(const double& v) const {
|
||||
return *this == Any(v);
|
||||
}
|
||||
|
||||
bool operator==(int v) const {
|
||||
return *this == Any(v);
|
||||
}
|
||||
|
||||
bool operator==(bool v) const {
|
||||
return *this == Any(v);
|
||||
}
|
||||
|
||||
bool operator!=(const Any& x) const;
|
||||
|
||||
bool operator!=(const std::string& s) const {
|
||||
return *this != Any(s);
|
||||
}
|
||||
|
||||
bool operator!=(const double& v) const {
|
||||
return *this != Any(v);
|
||||
}
|
||||
|
||||
bool operator!=(int v) const {
|
||||
return *this != Any(v);
|
||||
}
|
||||
|
||||
bool operator!=(bool v) const {
|
||||
return *this != Any(v);
|
||||
}
|
||||
|
||||
operator int() const;
|
||||
operator uint32() const;
|
||||
operator float() const;
|
||||
operator double() const;
|
||||
operator bool() const;
|
||||
operator std::string() const;
|
||||
|
||||
operator char() const {
|
||||
return char(int(*this));
|
||||
}
|
||||
|
||||
operator uint8() const {
|
||||
return uint8(int(*this));
|
||||
}
|
||||
|
||||
operator int16() const {
|
||||
return int16(int(*this));
|
||||
}
|
||||
|
||||
operator uint16() const {
|
||||
return uint16(int(*this));
|
||||
}
|
||||
|
||||
/** 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);
|
||||
@@ -591,33 +730,88 @@ public:
|
||||
void clear();
|
||||
|
||||
/** Parse from a file.
|
||||
\sa deserialize, parse */
|
||||
\sa deserialize, parse, fromFile, loadIfExists
|
||||
*/
|
||||
void load(const std::string& filename);
|
||||
|
||||
/** Load a new Any from \a filename. \sa load, save, loadIfExists */
|
||||
static Any fromFile(const std::string& filename);
|
||||
|
||||
/** Load \a filename file if it exists, otherwise do not modify this */
|
||||
void loadIfExists(const std::string& filename);
|
||||
|
||||
/** Uses the serialize method. */
|
||||
void save(const std::string& filename) const;
|
||||
|
||||
void serialize(TextOutput& to) const;
|
||||
void serialize(TextOutput& to, bool json = false, bool coerce = false) const;
|
||||
|
||||
void serialize(class BinaryOutput& b) const;
|
||||
|
||||
/** Parse from a stream.
|
||||
\sa load, parse */
|
||||
void deserialize(TextInput& ti);
|
||||
|
||||
void deserialize(class BinaryInput& b);
|
||||
|
||||
const Source& source() const;
|
||||
|
||||
/** Removes this key from the Any, which must be a table. */
|
||||
void remove(const std::string& key);
|
||||
|
||||
/** Removes this key from the Any, which must be an array, and
|
||||
shifts other elements down to maintain order. */
|
||||
void remove(int index);
|
||||
|
||||
/** 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).
|
||||
/** Verifies that the name is identifier \a n (case sensitive).
|
||||
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).
|
||||
/** Verifies that the name is identifier \a n or \a m (case sensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyName(const std::string& n, const std::string& m) const;
|
||||
|
||||
/** Verifies that the name is identifier \a n or \a m or \a p (case sensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyName(const std::string& n, const std::string& m, const std::string& p) const;
|
||||
|
||||
/** Verifies that the name is identifier \a n or \a m or \a p or \a q (case sensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyName(const std::string& n, const std::string& m, const std::string& p, const std::string& q) const;
|
||||
|
||||
/** Verifies that the name <i>begins with</i> identifier \a n (case sensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyNameBeginsWith(const std::string& n) const;
|
||||
|
||||
/** Verifies that the name <i>begins with</i> identifier \a n or \a m (case sensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyNameBeginsWith(const std::string& n, const std::string& m) const;
|
||||
|
||||
/** Verifies that the name <i>begins with</i> identifier \a n or \a m or \a p (case sensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p) const;
|
||||
|
||||
/** Verifies that the name <i>begins with</i> identifier \a n or \a m or \a p or \a q (case sensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q) const;
|
||||
|
||||
/** Verifies that the name <i>begins with</i> identifier \a n or \a m or \a p or \a q or \a r (case sensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q, const std::string& r) const;
|
||||
|
||||
/** Verifies that the name <i>begins with</i> identifier \a n or \a m or \a p or \a q or \a r or \a s (case sensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q, const std::string& r, const std::string& s) const;
|
||||
|
||||
/** Verifies that the name <i>begins with</i> identifier \a n or \a m or \a p or \a q or \a r or \a s or \a t(case sensitive).
|
||||
It may contain identifier operators after this */
|
||||
void verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q, const std::string& r, const std::string& s, const std::string& t) const;
|
||||
|
||||
/** Verifies that the type is \a t. */
|
||||
void verifyType(Type t) const;
|
||||
|
||||
@@ -630,14 +824,49 @@ public:
|
||||
/** Verifies that the size is exactly \a s */
|
||||
void verifySize(int s) const;
|
||||
|
||||
/** Assumes that Any(T) is well-defined, e.g., by T defining a
|
||||
T::toAny() method. */
|
||||
template<class T>
|
||||
explicit Any(const Array<T>& array, const std::string& name = "") : m_type(ARRAY), m_data(NULL) {
|
||||
setName(name);
|
||||
resize(array.size());
|
||||
for (int i = 0; i < array.size(); ++i) {
|
||||
(*this)[i] = Any(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Assumes that T defines T(const Any&) */
|
||||
template<class T>
|
||||
void getArray(Array<T>& array) const {
|
||||
verifyType(ARRAY);
|
||||
array.resize(size());
|
||||
for (int i = 0; i < array.size(); ++i) {
|
||||
array[i] = T((*this)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Assumes that T defines T(const Any&) */
|
||||
template<class T>
|
||||
void getTable(Table<std::string, T>& table) const {
|
||||
verifyType(TABLE);
|
||||
for (Table<std::string, Any>::Iterator it = this->table().begin(); it.isValid(); ++it) {
|
||||
table.set(it.key(), T(it.value()));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void deserializeTable(TextInput& ti);
|
||||
void deserializeArray(TextInput& ti,const std::string& term);
|
||||
|
||||
/** Turns an empty container into a table or an array */
|
||||
void become(const Type& t);
|
||||
|
||||
}; // class Any
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Convenient iteration over the keys of a Any::TABLE, usually
|
||||
for implementing construction of an object from an Any.
|
||||
@@ -647,14 +876,14 @@ private:
|
||||
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);
|
||||
\code
|
||||
AnyTableReader r(a);
|
||||
r.getIfPresent("enabled", enabled);
|
||||
r.getIfPresent("showSamples", showSamples);
|
||||
r.get("showTiles", showTiles);
|
||||
|
||||
r.verifyDone();
|
||||
</pre>
|
||||
\endcode
|
||||
|
||||
\beta
|
||||
*/
|
||||
@@ -665,44 +894,21 @@ private:
|
||||
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;
|
||||
}
|
||||
}
|
||||
AnyTableReader(const std::string& name, const Any& a);
|
||||
|
||||
/** 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;
|
||||
}
|
||||
}
|
||||
AnyTableReader(const Any& a);
|
||||
|
||||
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("");
|
||||
}
|
||||
void verifyDone() const;
|
||||
|
||||
/** Return the underlying Any. */
|
||||
const Any& any() const {
|
||||
return m_any;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -714,30 +920,67 @@ public:
|
||||
|
||||
AnyKeyIterator& operator++();
|
||||
#endif
|
||||
|
||||
/** \copydoc get(const std::string& s, ValueType& v) */
|
||||
void get(const std::string& s, std::string& v) {
|
||||
v = m_any[s].string();
|
||||
m_alreadyRead.insert(s);
|
||||
}
|
||||
|
||||
/** \copydoc get(const std::string& s, ValueType& v) */
|
||||
void get(const std::string& s, uint8& v) {
|
||||
v = uint8(m_any[s].number());
|
||||
m_alreadyRead.insert(s);
|
||||
}
|
||||
|
||||
/** \copydoc get(const std::string& s, ValueType& v) */
|
||||
void get(const std::string& s, uint16& v) {
|
||||
v = uint16(m_any[s].number());
|
||||
m_alreadyRead.insert(s);
|
||||
}
|
||||
|
||||
/** Read an entire array at once.*/
|
||||
template<class T>
|
||||
void get(const std::string& s, Array<T>& v) {
|
||||
m_any[s].getArray(v);
|
||||
m_alreadyRead.insert(s);
|
||||
}
|
||||
|
||||
/** If key \s appears in the any, reads its value into \a v and
|
||||
template<class T>
|
||||
void get(const std::string& s, Table<std::string, T>& v) {
|
||||
m_any[s].getTable(v);
|
||||
m_alreadyRead.insert(s);
|
||||
}
|
||||
|
||||
/** If key \a 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.
|
||||
If key \a 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
|
||||
Assumes that if key \a 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));
|
||||
v = ValueType(m_any[s]);
|
||||
m_alreadyRead.insert(s);
|
||||
}
|
||||
|
||||
/** Same as get() */
|
||||
const Any& operator[](const std::string& s) {
|
||||
m_alreadyRead.insert(s);
|
||||
return m_any[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
|
||||
If key \a 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.
|
||||
If key \a s does not appear in the any, does nothing.
|
||||
|
||||
Assumes that if key \s appears in the any it has not already been extracted
|
||||
Assumes that if key \a 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.
|
||||
@@ -745,7 +988,7 @@ public:
|
||||
template<class ValueType>
|
||||
bool getIfPresent(const std::string& s, ValueType& v) {
|
||||
if (m_any.containsKey(s)) {
|
||||
debugAssertM(! m_alreadyRead.contains(toLower(s)), "read twice");
|
||||
debugAssertM(! m_alreadyRead.contains(s), "read twice");
|
||||
|
||||
get(s, v);
|
||||
return true;
|
||||
@@ -753,8 +996,29 @@ public:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** \return True if \a s is in the table and has not yet been read
|
||||
using get() or getIfPresent(). */
|
||||
bool containsUnread(const std::string& s) const {
|
||||
return m_any.containsKey(s) && ! m_alreadyRead.contains(s);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace G3D
|
||||
|
||||
|
||||
/**
|
||||
\def PARSE_ANY(expression)
|
||||
|
||||
\brief Create an G3D::Any from an unquoted string.
|
||||
|
||||
e.g.,
|
||||
\code
|
||||
Any x = PARSE_ANY( { a = 3.0; b = false; } );
|
||||
\endcode
|
||||
*/
|
||||
#define PARSE_ANY(x) Any::parse(#x)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user