/** @file AnyVal.cpp @author Morgan McGuire @maintainer Morgan McGuire @created 2006-06-11 @edited 2008-07-14 */ #include "G3D/AnyVal.h" #include "G3D/Array.h" #include "G3D/stringutils.h" #include "G3D/Table.h" #include "G3D/Vector2.h" #include "G3D/Vector3.h" #include "G3D/Vector4.h" #include "G3D/Color1.h" #include "G3D/Color3.h" #include "G3D/Color4.h" #include "G3D/Matrix2.h" #include "G3D/Matrix3.h" #include "G3D/Matrix4.h" #include "G3D/Rect2D.h" #include "G3D/AABox.h" #include "G3D/CoordinateFrame.h" #include "G3D/Quat.h" #include "G3D/TextInput.h" #include "G3D/TextOutput.h" #include "G3D/BinaryInput.h" #include "G3D/BinaryOutput.h" namespace G3D { AnyVal AnyVal::fromFile(const std::string& filename) { TextInput t(filename); return AnyVal(t); } void AnyVal::load(const std::string& filename) { *this = fromFile(filename); } void AnyVal::save(const std::string& filename) const { TextOutput t(filename); serialize(t); t.commit(); } AnyVal::AnyVal() : m_type(NIL), m_value(NULL), m_referenceCount(NULL) { } AnyVal::AnyVal(bool b) : m_type(BOOLEAN), m_value(new bool(b)), m_referenceCount(NULL) { } AnyVal::AnyVal(G3D::TextInput& t) : m_type(NIL), m_value(NULL), m_referenceCount(NULL) { deserialize(t); } /*AnyVal::AnyVal(G3D::BinaryInput& b) { deserialize(b); } */ AnyVal::AnyVal(double v) : m_type(NUMBER), m_referenceCount(NULL) { m_value = new double(v); } AnyVal::AnyVal(int v) : m_type(NUMBER), m_referenceCount(NULL) { m_value = new double(v); } AnyVal::AnyVal(const Rect2D& v) : m_type(RECT2D), m_referenceCount(NULL) { m_value = new Rect2D(v); } AnyVal::AnyVal(const AABox& v) : m_type(AABOX), m_referenceCount(NULL) { m_value = new AABox(v); } AnyVal::AnyVal(const Vector2& v) : m_type(VECTOR2), m_referenceCount(NULL) { m_value = new Vector2(v); } AnyVal::AnyVal(const Vector3& v) : m_type(VECTOR3), m_referenceCount(NULL) { m_value = new Vector3(v); } AnyVal::AnyVal(const Vector4& v) : m_type(VECTOR4), m_referenceCount(NULL) { m_value = new Vector4(v); } AnyVal::AnyVal(const Color1& v) : m_type(COLOR1), m_referenceCount(NULL) { m_value = new Color1(v); } AnyVal::AnyVal(const Color3& v) : m_type(COLOR3), m_referenceCount(NULL) { m_value = new Color3(v); } AnyVal::AnyVal(const Color4& v) : m_type(COLOR4), m_referenceCount(NULL) { m_value = new Color4(v); } AnyVal::AnyVal(const std::string& v) : m_type(STRING), m_referenceCount(NULL) { m_value = new std::string(v); } AnyVal::AnyVal(const char* v) : m_type(STRING), m_referenceCount(NULL) { m_value = new std::string(v); } AnyVal::AnyVal(const Quat& v) : m_type(QUAT), m_referenceCount(NULL) { m_value = new Quat(v); } AnyVal::AnyVal(const CoordinateFrame& v) : m_type(COORDINATEFRAME), m_referenceCount(NULL) { m_value = new CoordinateFrame(v); } AnyVal::AnyVal(const Matrix2& v) : m_type(MATRIX2), m_referenceCount(NULL) { m_value = new Matrix2(v); } AnyVal::AnyVal(const Matrix3& v) : m_type(MATRIX3), m_referenceCount(NULL) { m_value = new Matrix3(v); } AnyVal::AnyVal(const Matrix4& v) : m_type(MATRIX4), m_referenceCount(NULL) { m_value = new Matrix4(v); } AnyVal::AnyVal(const AnyVal& c) : m_type(NIL), m_value(NULL), m_referenceCount(NULL) { *this = c; } AnyVal::AnyVal(Type arrayOrTable) : m_type(NIL), m_value(NULL), m_referenceCount(new int(1)) { // TODO: make AnyVal::createArray() switch (arrayOrTable) { case ARRAY: m_type = ARRAY; m_value = new Array(); break; case TABLE: m_type = TABLE; m_value = new Table(); break; default: debugAssertM(false, "Cannot construct AnyVal from constants except ARRAY or TABLE."); } } AnyVal::~AnyVal() { deleteValue(); } void AnyVal::deleteValue() { if (m_referenceCount) { --(*m_referenceCount); if (*m_referenceCount <= 0) { delete m_referenceCount; m_referenceCount = NULL; // Pass through and delete the real object now } else { // Someone else is holding a reference, so we can't delete // the object. m_referenceCount = NULL; return; } } switch (m_type) { case NIL: // Nothing to do break; case NUMBER: delete (double*)m_value; break; case BOOLEAN: delete (bool*)m_value; break; case STRING: delete (std::string*)m_value; break; case RECT2D: delete (Rect2D*)m_value; break; case AABOX: delete (AABox*)m_value; break; case VECTOR2: delete (Vector2*)m_value; break; case VECTOR3: delete (Vector3*)m_value; break; case VECTOR4: delete (Vector4*)m_value; break; case MATRIX2: delete (Matrix2*)m_value; break; case MATRIX3: delete (Matrix3*)m_value; break; case MATRIX4: delete (Matrix4*)m_value; break; case QUAT: delete (Quat*)m_value; break; case COORDINATEFRAME: delete (CoordinateFrame*)m_value; break; case COLOR1: delete (Color1*)m_value; break; case COLOR3: delete (Color3*)m_value; break; case COLOR4: delete (Color4*)m_value; break; case ARRAY: delete (Array*)m_value; break; case TABLE: delete (Table*)m_value; break; default: debugAssertM(false, "Internal error: no destructor for this type."); } m_value = NULL; } AnyVal& AnyVal::operator=(const AnyVal& v) { deleteValue(); m_type = v.m_type; m_referenceCount = v.m_referenceCount; if (isSharedType()) { ++(*m_referenceCount); m_value = v.m_value; } else { m_value = v.copyValue(); } return *this; } void* AnyVal::copyValue() const { switch (m_type) { case NIL: return NULL; case NUMBER: return new double(*(double*)m_value); case BOOLEAN: return new bool(*(bool*)m_value); case STRING: return new std::string(*(std::string*)m_value); case RECT2D: return new Rect2D(*(Rect2D*)m_value); case AABOX: return new AABox(*(AABox*)m_value); case VECTOR2: return new Vector2(*(Vector2*)m_value); case VECTOR3: return new Vector3(*(Vector3*)m_value); case VECTOR4: return new Vector4(*(Vector4*)m_value); case MATRIX2: return new Matrix2(*(Matrix2*)m_value); case MATRIX3: return new Matrix3(*(Matrix3*)m_value); case MATRIX4: return new Matrix4(*(Matrix4*)m_value); case QUAT: return new Quat(*(Quat*)m_value); case COORDINATEFRAME: return new CoordinateFrame(*(CoordinateFrame*)m_value); case COLOR1: return new Color1(*(Color1*)m_value); case COLOR3: return new Color3(*(Color3*)m_value); case COLOR4: return new Color4(*(Color4*)m_value); case ARRAY: return new Array(*(Array*)m_value); case TABLE: return new Table(*(Table*)m_value); default: debugAssertM(false, "Internal error: no assignment operator for this type."); return NULL; } } AnyVal::Type AnyVal::type() const { return m_type; } static bool legalIdentifier(const std::string& s) { if (s.size() == 0) { return false; } if (! isLetter(s[0]) || (s[0] == '_')) { return false; } bool ok = true; for (unsigned int i = 1; i < s.size(); ++i) { ok &= isDigit(s[i]) || isLetter(s[i]) || (s[i] == '_'); } return ok; } void AnyVal::serialize(G3D::TextOutput& t) const { switch (m_type) { case NIL: t.writeSymbol("Nil"); break; case NUMBER: t.printf("%g", *(double*)m_value); break; case BOOLEAN: t.writeBoolean(*(bool*)m_value); break; case STRING: t.writeString(*(std::string*)m_value); break; case RECT2D: t.printf("R(%g, %g, %g, %g)", ((Rect2D*)m_value)->x0(), ((Rect2D*)m_value)->y0(), ((Rect2D*)m_value)->width(), ((Rect2D*)m_value)->height()); break; case AABOX: t.printf("AAB(V3(%g, %g, %g), V3(%g, %g, %g))", aabox().low().x, aabox().low().y, aabox().low().z, aabox().high().x, aabox().high().y, aabox().high().z); break; case VECTOR2: t.printf("V2(%g, %g)", ((Vector2*)m_value)->x, ((Vector2*)m_value)->y); break; case VECTOR3: t.printf("V3(%g, %g, %g)", ((Vector3*)m_value)->x, ((Vector3*)m_value)->y, ((Vector3*)m_value)->z); break; case VECTOR4: t.printf("V4(%g, %g, %g, %g)", ((Vector4*)m_value)->x, ((Vector4*)m_value)->y, ((Vector4*)m_value)->z, ((Vector4*)m_value)->w); break; case MATRIX2: { const Matrix2& m = *(Matrix2*)m_value; t.printf("M2(\n"); t.pushIndent(); t.printf("%10.5f, %10.5f,\n%10.5f, %10.5f)", m[0][0], m[0][1], m[1][0], m[1][1]); t.popIndent(); } break; case MATRIX3: { const Matrix3& m = *(Matrix3*)m_value; t.printf("M3(\n"); t.pushIndent(); t.printf("%10.5f, %10.5f, %10.5f,\n%10.5f, %10.5f, %10.5f,\n%10.5f, %10.5f, %10.5f)", m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2]); t.popIndent(); } break; case MATRIX4: { const Matrix4& m = *(Matrix4*)m_value; t.printf("M4(\n"); t.pushIndent(); t.printf( "%10.5f, %10.5f, %10.5f, %10.5f,\n" "%10.5f, %10.5f, %10.5f, %10.5f,\n" "%10.5f, %10.5f, %10.5f, %10.5f,\n" "%10.5f, %10.5f, %10.5f, %10.5f)", m[0][0], m[0][1], m[0][2], m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3], m[3][0], m[3][1], m[3][2], m[3][3]); t.popIndent(); } break; case QUAT: t.printf("Q(%g, %g, %g, %g)", ((Quat*)m_value)->x, ((Quat*)m_value)->y, ((Quat*)m_value)->z, ((Quat*)m_value)->w); break; case COORDINATEFRAME: { const CoordinateFrame& c = *(CoordinateFrame*)m_value; float x,y,z,yaw,pitch,roll; c.getXYZYPRDegrees(x,y,z,yaw,pitch,roll); t.printf("CF(V3(%g,%g,%g), %g, %g, %g)", x, y, z, yaw, pitch, roll); /* t.pushIndent(); t.printf( "CF(\n%10.5f, %10.5f, %10.5f, %10.5f,\n" "%10.5f, %10.5f, %10.5f, %10.5f,\n" "%10.5f, %10.5f, %10.5f, %10.5f)", c.rotation[0][0], c.rotation[0][1], c.rotation[0][2], c.translation.x, c.rotation[1][0], c.rotation[1][1], c.rotation[1][2], c.translation.y, c.rotation[2][0], c.rotation[2][1], c.rotation[2][2], c.translation.z); t.popIndent(); */ } break; case COLOR1: t.printf("C1(%g)", ((Color1*)m_value)->value); break; case COLOR3: t.printf("C3(%g, %g, %g)", ((Color3*)m_value)->r, ((Color3*)m_value)->g, ((Color3*)m_value)->b); break; case COLOR4: t.printf("C4(%g, %g, %g, %g)", ((Color4*)m_value)->r, ((Color4*)m_value)->g, ((Color4*)m_value)->b, ((Color4*)m_value)->a); break; case ARRAY: { const Array& a = *(Array*)m_value; t.printf("[\n"); t.pushIndent(); for (int i = 0; i < a.size(); ++i) { a[i].serialize(t); if (i != a.size() - 1) { t.printf(", \n"); } } t.printf("]"); t.popIndent(); } break; case TABLE: { const Table& a = *(Table*)m_value; t.printf("{\n"); t.pushIndent(); Table::Iterator i = a.begin(); const Table::Iterator end = a.end(); while (i != end) { // Quote names that are not legal C++ identifiers if (! legalIdentifier(i->key)) { t.printf("'%s' ", i->key.c_str()); } else { t.writeSymbol(i->key); } t.printf("= "); i->value.serialize(t); if (i != end) { t.printf("\n"); } ++i; } t.popIndent(); t.printf("}"); } break; default: debugAssertM(false, "Internal error: no serialize method for this type."); } } std::string AnyVal::toString() const { TextOutput t; serialize(t); std::string s; t.commitString(s); return s; } void AnyVal::deserialize(G3D::TextInput& t) { deleteValue(); m_type = NIL; m_value = NULL; if (! t.hasMore()) { return; } switch (t.peek().type()) { case Token::END: // should never get here because of the hasMore check above return; break; case Token::NUMBER: m_type = NUMBER; m_value = new double(t.readNumber()); break; case Token::STRING: m_type = STRING; m_value = new std::string(t.readString()); break; case Token::NEWLINE: m_type = STRING; m_value = new std::string(t.readNewline()); break; case Token::COMMENT: m_type = STRING; m_value = new std::string(t.readComment()); break; case Token::BOOLEAN: m_type = BOOLEAN; m_value = new bool(t.readBoolean()); break; case Token::SYMBOL: { std::string s = t.readSymbol(); if (s == "NIL") { break; } else if (s == "true") { m_type = BOOLEAN; m_value = new bool(true); } else if (s == "false") { m_type = BOOLEAN; m_value = new bool(false); } else if (s == "R") { m_type = RECT2D; t.readSymbol("("); float x,y,w,h; x = (float)t.readNumber(); t.readSymbol(","); y = (float)t.readNumber(); t.readSymbol(","); w = (float)t.readNumber(); t.readSymbol(","); h = (float)t.readNumber(); t.readSymbol(")"); m_value = new Rect2D(Rect2D::xywh(x, y, w, h)); } else if (s == "AAB") { m_type = AABOX; Vector3 v[2]; t.readSymbol("("); for (int i = 0; i < 2; ++i) { t.readSymbols("V3", "("); v[i].x = (float)t.readNumber(); t.readSymbol(","); v[i].y = (float)t.readNumber(); t.readSymbol(","); v[i].z = (float)t.readNumber(); t.readSymbol(","); if (i == 0) { t.readSymbol(","); } } t.readSymbol(")"); m_value = new AABox(v[0], v[1]); } else if (s == "V2") { t.readSymbol("("); Vector2 v; v.x = (float)t.readNumber(); t.readSymbol(","); v.y = (float)t.readNumber(); t.readSymbol(")"); m_value = new Vector2(v); m_type = VECTOR2; } else if (s == "V3") { t.readSymbol("("); Vector3 v; v.x = (float)t.readNumber(); t.readSymbol(","); v.y = (float)t.readNumber(); t.readSymbol(","); v.z = (float)t.readNumber(); t.readSymbol(")"); m_value = new Vector3(v); m_type = VECTOR3; } else if (s == "V4") { t.readSymbol("("); Vector4 v; v.x = (float)t.readNumber(); t.readSymbol(","); v.y = (float)t.readNumber(); t.readSymbol(","); v.z = (float)t.readNumber(); t.readSymbol(","); v.w = (float)t.readNumber(); t.readSymbol(")"); m_value = new Vector4(v); m_type = VECTOR4; } else if (s == "M2") { t.readSymbol("("); Matrix2 m; for (int r = 0; r < 2; ++r) { for (int c = 0; c < 2; ++c) { m[r][c] = (float)t.readNumber(); if ((c != 1) || (r != 1)) { t.readSymbol(","); } } } t.readSymbol(")"); m_value = new Matrix2(m); m_type = MATRIX2; } else if (s == "M3") { t.readSymbol("("); Matrix3 m; for (int r = 0; r < 3; ++r) { for (int c = 0; c < 3; ++c) { m[r][c] = (float)t.readNumber(); if ((c != 2) || (r != 2)) { t.readSymbol(","); } } } t.readSymbol(")"); m_value = new Matrix3(m); m_type = MATRIX3; } else if (s == "M4") { t.readSymbol("("); Matrix4 m; for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) { m[r][c] = (float)t.readNumber(); if ((c != 3) || (r != 3)) { t.readSymbol(","); } } } t.readSymbol(")"); m_value = new Matrix4(m); m_type = MATRIX4; } else if (s == "Q") { t.readSymbol("("); Quat q; q.x = (float)t.readNumber(); t.readSymbol(","); q.y = (float)t.readNumber(); t.readSymbol(","); q.z = (float)t.readNumber(); t.readSymbol(","); q.w = (float)t.readNumber(); t.readSymbol(")"); m_value = new Quat(q); m_type = QUAT; } else if (s == "CF") { t.readSymbol("("); CoordinateFrame m; if (t.peek().type() == Token::SYMBOL) { // Angle format float x, y, z, yaw, roll, pitch; t.readSymbols("V3", "("); x = (float)t.readNumber(); t.readSymbol(","); y = (float)t.readNumber(); t.readSymbol(","); z = (float)t.readNumber(); t.readSymbols(")", ","); yaw = (float)t.readNumber(); t.readSymbol(","); pitch = (float)t.readNumber(); roll = 0; if (t.peek().string() == ",") { t.readSymbol(","); roll = (float)t.readNumber(); } m = CoordinateFrame::fromXYZYPRDegrees(x, y, z, yaw, pitch, roll); } else { // Matrix format for (int r = 0; r < 3; ++r) { for (int c = 0; c < 3; ++c) { m.rotation[r][c] = (float)t.readNumber(); } m.translation[r] = (float)t.readNumber(); if (r != 2) { t.readSymbol(","); } } } t.readSymbol(")"); m_value = new CoordinateFrame(m); m_type = COORDINATEFRAME; } else if (s == "C1") { t.readSymbol("("); float v = (float)t.readNumber(); t.readSymbol(")"); m_value = new Color1(v); m_type = COLOR1; } else if (s == "C3") { t.readSymbol("("); Color3 c; c.r = (float)t.readNumber(); t.readSymbol(","); c.g = (float)t.readNumber(); t.readSymbol(","); c.b = (float)t.readNumber(); t.readSymbol(")"); m_value = new Color3(c); m_type = COLOR3; } else if (s == "C4") { t.readSymbol("("); Color4 c; c.r = (float)t.readNumber(); t.readSymbol(","); c.g = (float)t.readNumber(); t.readSymbol(","); c.b = (float)t.readNumber(); t.readSymbol(","); c.a = (float)t.readNumber(); t.readSymbol(")"); m_value = new Color4(c); m_type = COLOR4; } else if (s == "[") { // Array m_type = ARRAY; m_value = new Array(); m_referenceCount = new int(1); Array& a = *(Array*)m_value; Token peek = t.peek(); while ((peek.type() != Token::SYMBOL) || (peek.string() != "]")) { // Avoid copying large objects a.next().deserialize(t); peek = t.peek(); if (peek.type() != Token::SYMBOL) { throw CorruptText("Expected ',' or ']'", peek); } else if (peek.string() == ",") { t.readSymbol(","); } else if (peek.string() != "]") { throw CorruptText("Missing ']'", peek); } } t.readSymbol("]"); } else if (s == "{") { // Table m_type = TABLE; m_value = new Table(); m_referenceCount = new int(1); Table& a = *(Table*)m_value; Token peek = t.peek(); while ((peek.type() != Token::SYMBOL) || (peek.string() != "}")) { std::string key; // Get the name if (peek.type() == Token::SYMBOL) { key = t.readSymbol(); } else if (peek.extendedType() == Token::SINGLE_QUOTED_TYPE) { key = t.readString(); } else { throw CorruptText("Expected name inside table", peek); } t.readSymbol("="); // Avoid copying large values a.set(key, AnyVal()); a[key].deserialize(t); peek = t.peek(); if ((peek.type() != Token::SYMBOL) && (peek.extendedType() != Token::SINGLE_QUOTED_TYPE)) { throw CorruptText("Missing expected name or '}'", peek); } } t.readSymbol("}"); } else { throw CorruptText("Invalid value type.", t.peek()); } // dispatch on symbol type } // scope break; } } AnyVal& AnyVal::operator[](const char* key) { return this->operator[]((std::string)key); } const AnyVal& AnyVal::operator[](const char* key) const { return this->operator[]((std::string)key); } AnyVal& AnyVal::operator[](const std::string& key) { if (m_type != TABLE) { throw WrongType(TABLE, m_type); } makeMutable(); Table& t = *(Table*)m_value; if (! t.containsKey(key)) { t.set(key, AnyVal()); } return t[key]; } const AnyVal& AnyVal::operator[](const std::string& key) const { if (m_type != TABLE) { throw WrongType(TABLE, m_type); } const Table& t = *(const Table*)m_value; if (! t.containsKey(key)) { throw KeyNotFound(key); } return t[key]; } void AnyVal::append(const AnyVal& v) { if (m_type != ARRAY) { throw WrongType(ARRAY, m_type); } makeMutable(); Array& a = *(Array*)m_value; a.append(v); } void AnyVal::getKeys(Array& keys) const { if (m_type != TABLE) { throw WrongType(TABLE, m_type); } const Table& t = *(const Table*)m_value; t.getKeys(keys); } int AnyVal::size() const { switch (m_type) { case TABLE: { const Table& t = *(const Table*)m_value; return t.size(); } case ARRAY: { const Array& a = *(Array*)m_value; return a.size(); } default: throw WrongType(ARRAY, m_type); } } AnyVal& AnyVal::operator[](int i) { if (m_type != ARRAY) { throw WrongType(ARRAY, m_type); } makeMutable(); Array& a = *(Array*)m_value; if (i < 0) { throw IndexOutOfBounds(i, a.size()); } if (a.size() <= i) { a.resize(i + 1); } return a[i]; } const AnyVal& AnyVal::operator[](int i) const { if (m_type != ARRAY) { throw WrongType(ARRAY, m_type); } const Array& a = *(Array*)m_value; if (a.size() <= i || i < 0) { throw IndexOutOfBounds(i, a.size()); } return a[i]; } void AnyVal::makeMutable() { if (*m_referenceCount > 1) { // This is a shared instance --(*m_referenceCount); m_referenceCount = new int(1); m_value = copyValue(); } } bool AnyVal::boolean() const { if (m_type != BOOLEAN) { throw WrongType(BOOLEAN, m_type); } return *(bool*)m_value; } bool AnyVal::boolean(bool defaultVal) const { if (m_type != BOOLEAN) { return defaultVal; } return *(bool*)m_value; } const std::string& AnyVal::string() const { if (m_type != STRING) { throw WrongType(STRING, m_type); } return *(std::string*)m_value; } const std::string& AnyVal::string(const std::string& defaultVal) const { if (m_type != STRING) { return defaultVal; } else { return *(std::string*)m_value; } } double AnyVal::number() const { if (m_type != NUMBER) { throw WrongType(NUMBER, m_type); } return *(double*)m_value; } double AnyVal::number(double defaultVal) const { if (m_type != NUMBER) { return defaultVal; } else { return *(double*)m_value; } } const Rect2D& AnyVal::rect2D() const { if (m_type != RECT2D) { throw WrongType(RECT2D, m_type); } return *(Rect2D*)m_value; } const Rect2D& AnyVal::rect2D(const Rect2D& defaultVal) const { if (m_type != RECT2D) { return defaultVal; } else { return *(Rect2D*)m_value; } } const AABox& AnyVal::aabox() const { if (m_type != AABOX) { throw WrongType(AABOX, m_type); } return *(AABox*)m_value; } const AABox& AnyVal::aabox(const AABox& defaultVal) const { if (m_type != AABOX) { return defaultVal; } else { return *(AABox*)m_value; } } const Color1& AnyVal::color1() const { if (m_type != COLOR1) { throw WrongType(COLOR1, m_type); } return *(Color1*)m_value; } const Color1& AnyVal::color1(const Color1& defaultVal) const { if (m_type != COLOR1) { return defaultVal; } else { return *(Color1*)m_value; } } const Color3& AnyVal::color3() const { if (m_type != COLOR3) { throw WrongType(COLOR3, m_type); } return *(Color3*)m_value; } const Color3& AnyVal::color3(const Color3& defaultVal) const { if (m_type != COLOR3) { return defaultVal; } else { return *(Color3*)m_value; } } const Color4& AnyVal::color4() const { if (m_type != COLOR4) { throw WrongType(COLOR4, m_type); } return *(Color4*)m_value; } const Color4& AnyVal::color4(const Color4& defaultVal) const { if (m_type != COLOR4) { return defaultVal; } else { return *(Color4*)m_value; } } const Vector2& AnyVal::vector2() const { if (m_type != VECTOR2) { throw WrongType(VECTOR2, m_type); } return *(Vector2*)m_value; } const Vector2& AnyVal::vector2(const Vector2& defaultVal) const { if (m_type != VECTOR2) { return defaultVal; } else { return *(Vector2*)m_value; } } const Vector3& AnyVal::vector3() const { if (m_type != VECTOR3) { throw WrongType(VECTOR3, m_type); } return *(Vector3*)m_value; } const Vector3& AnyVal::vector3(const Vector3& defaultVal) const { if (m_type != VECTOR3) { return defaultVal; } else { return *(Vector3*)m_value; } } const Vector4& AnyVal::vector4() const { if (m_type != VECTOR4) { throw WrongType(VECTOR4, m_type); } return *(Vector4*)m_value; } const Vector4& AnyVal::vector4(const Vector4& defaultVal) const { if (m_type != VECTOR4) { return defaultVal; } else { return *(Vector4*)m_value; } } const CoordinateFrame& AnyVal::coordinateFrame() const { if (m_type != COORDINATEFRAME) { throw WrongType(COORDINATEFRAME, m_type); } return *(CoordinateFrame*)m_value; } const CoordinateFrame& AnyVal::coordinateFrame(const CoordinateFrame& defaultVal) const { if (m_type != COORDINATEFRAME) { return defaultVal; } else { return *(CoordinateFrame*)m_value; } } const Matrix2& AnyVal::matrix2(const Matrix2& defaultVal) const { if (m_type != MATRIX2) { return defaultVal; } else { return *(Matrix2*)m_value; } } const Matrix2& AnyVal::matrix2() const { if (m_type != MATRIX2) { throw WrongType(MATRIX2, m_type); } return *(Matrix2*)m_value; } const Matrix3& AnyVal::matrix3(const Matrix3& defaultVal) const { if (m_type != MATRIX3) { return defaultVal; } else { return *(Matrix3*)m_value; } } const Matrix3& AnyVal::matrix3() const { if (m_type != MATRIX3) { throw WrongType(MATRIX3, m_type); } return *(Matrix3*)m_value; } const Matrix4& AnyVal::matrix4(const Matrix4& defaultVal) const { if (m_type != MATRIX4) { return defaultVal; } else { return *(Matrix4*)m_value; } } const Matrix4& AnyVal::matrix4() const { if (m_type != MATRIX4) { throw WrongType(MATRIX4, m_type); } return *(Matrix4*)m_value; } const Quat& AnyVal::quat(const Quat& defaultVal) const { if (m_type != QUAT) { return defaultVal; } else { return *(Quat*)m_value; } } const Quat& AnyVal::quat() const { if (m_type != QUAT) { throw WrongType(QUAT, m_type); } return *(Quat*)m_value; } const AnyVal& AnyVal::get(const std::string& key, const AnyVal& defaultVal) const { if (m_type != TABLE) { return defaultVal; } const Table& t = *(const Table*)m_value; if (t.containsKey(key)) { return t[key]; } else { return defaultVal; } } const AnyVal& AnyVal::get(const std::string& key) const { if (m_type != TABLE) { throw WrongType(TABLE, m_type); } const Table& t = *(const Table*)m_value; if (t.containsKey(key)) { return t[key]; } else { throw KeyNotFound(key); } } const AnyVal& AnyVal::get(int i, const AnyVal& defaultVal) const { if (m_type != ARRAY) { return defaultVal; } const Array& a = *(const Array*)m_value; if ((i >= 0) && (i < a.size())) { return a[i]; } else { return defaultVal; } } const AnyVal& AnyVal::get(int i) const { if (m_type != ARRAY) { throw WrongType(ARRAY, m_type); } const Array& a = *(const Array*)m_value; if ((i >= 0) && (i < a.size())) { return a[i]; } else { throw IndexOutOfBounds(i, a.size()); } } }