/******************************************************************************** * * * V a r i a n t T y p e * * * ********************************************************************************* * Copyright (C) 2013,2024 by Jeroen van der Zijp. All Rights Reserved. * ********************************************************************************* * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public License * * along with this program. If not, see * ********************************************************************************/ #ifndef FXVARIANT_H #define FXVARIANT_H namespace FX { class FXString; class FXVariantMap; class FXVariantArray; /** * A Variant type can hold any kind of object, be it a boolean, integer, real, string, * or even array of Variants or dictionaries of variants. * Complex hierarchies of Variants can be loaded (and saved) using the JSON parser. * When writing Variants, dictionaries and arrays are automatically grown. When * reading Variants, non-existing dictionary entries or indexes outside arrays will read * as 0 (for numbers), the empty string, or as an empty dictionary or array. * For efficiency, you can hold references to Variants, for example to avoid repeatedly * accessing dictionaries or arrays with the same key or index. However, be aware that * adding or removing sub-items to dictionaries or arrays may cause reallocations of * existing items and thus some care must be exercised when doing this. */ class FXAPI FXVariant { public: enum Type { NullType=0, // Simple types BoolType, CharType, IntType, UIntType, LongType, ULongType, FloatType, DoubleType, PointerType, StringType, // Complex types ArrayType, MapType }; private: union Value { FXlong i; // Signed integral types FXulong u; // Unsigned integral types FXdouble d; // Floating point types FXchar* s; // Character string FXptr p; // Pointer types }; private: Value value; // Current value Type type; // Type of value private: void init(Type t); public: /// Default constructor makes null type FXVariant(); /// Copy constructor FXVariant(const FXVariant& other); /// Construct and initialize with bool explicit FXVariant(FXbool val); /// Construct and initialize with char explicit FXVariant(FXchar val); /// Construct and initialize with int explicit FXVariant(FXint val); /// Construct and initialize with unsigned int explicit FXVariant(FXuint val); /// Construct and initialize with long explicit FXVariant(FXlong val); /// Construct and initialize with unsigned long explicit FXVariant(FXulong val); /// Construct and initialize with float explicit FXVariant(FXfloat val); /// Construct and initialize with double explicit FXVariant(FXdouble val); /// Construct and initialize with pointer explicit FXVariant(FXptr val); /// Construct and initialize with constant string explicit FXVariant(const FXchar *val); /// Construct and initialize with string explicit FXVariant(const FXString& val); /// Change type void setType(Type t); /// Return type Type getType() const { return type; } /// Return size of array FXival no() const; /// Change number of elements in array FXbool no(FXival n); /// Is it a null? FXbool isNull() const { return type==NullType; } /// Is it a bool? FXbool isBool() const { return type==BoolType; } /// Is it a character? FXbool isChar() const { return type==CharType; } /// Is it a int? FXbool isInt() const { return type==IntType; } /// Is it a unsigned int? FXbool isUInt() const { return type==UIntType; } /// Is it a long? FXbool isLong() const { return type==LongType; } /// Is it a unsigned long? FXbool isULong() const { return type==ULongType; } /// Is it a float? FXbool isFloat() const { return type==FloatType; } /// Is it a double? FXbool isDouble() const { return type==DoubleType; } /// Is it a integer (bool, char, ..., or long)? FXbool isInteger() const { return BoolType<=type && type<=ULongType; } /// Is it a real (float or double)? FXbool isReal() const { return FloatType<=type && type<=DoubleType; } /// Is it any kind of number? FXbool isNumber() const { return BoolType<=type && type<=DoubleType; } /// Is it a pointer? FXbool isPtr() const { return type==PointerType; } /// Is it a string? FXbool isString() const { return type==StringType; } /// Is it a array? FXbool isArray() const { return type==ArrayType; } /// Is it a map? FXbool isMap() const { return type==MapType; } /// Convert to bool; always OK FXbool toBool() const; /// Convert to pointer FXptr toPtr() const; /// Convert to int FXint toInt(FXbool* ok=nullptr) const; /// Convert to unsigned int FXuint toUInt(FXbool* ok=nullptr) const; /// Convert to long FXlong toLong(FXbool* ok=nullptr) const; /// Convert to unsigned long FXulong toULong(FXbool* ok=nullptr) const; /// Convert to float FXfloat toFloat(FXbool* ok=nullptr) const; /// Convert to double FXdouble toDouble(FXbool* ok=nullptr) const; /// Convert to char pointer const FXchar* toChars() const; /// Convert to string FXString toString(FXbool* ok=nullptr) const; /// Convert to bool operator FXbool() const { return toBool(); } /// Convert to pointer operator FXptr() const { return toPtr(); } /// Convert to char operator FXchar() const { return (FXchar)toInt(); } /// Convert to unsigned char operator FXuchar() const { return (FXuchar)toUInt(); } /// Convert to short operator FXshort() const { return (FXshort)toInt(); } /// Convert to unsigned short operator FXushort() const { return (FXushort)toUInt(); } /// Convert to int operator FXint() const { return toInt(); } /// Convert to unsigned int operator FXuint() const { return toUInt(); } /// Convert to long operator FXlong() const { return toLong(); } /// Convert to unsigned long operator FXulong() const { return toULong(); } /// Convert to float operator FXfloat() const { return toFloat(); } /// Convert to double operator FXdouble() const { return toDouble(); } /// Convert to string operator FXString() const { return toString(); } /// Assign with bool FXVariant& operator=(FXbool val); /// Assign with char FXVariant& operator=(FXchar val); /// Assign with int FXVariant& operator=(FXint val); /// Assign with unsigned int FXVariant& operator=(FXuint val); /// Assign with long FXVariant& operator=(FXlong val); /// Assign with unsigned long FXVariant& operator=(FXulong val); /// Assign with float FXVariant& operator=(FXfloat val); /// Assign with double FXVariant& operator=(FXdouble val); /// Assign with pointer FXVariant& operator=(FXptr val); /// Assign with constant string FXVariant& operator=(const FXchar* val); /// Assign with string FXVariant& operator=(const FXString& val); /// Assign with variant FXVariant& operator=(const FXVariant& val); /// Assign with variant FXVariant& assign(const FXVariant& other); /// Adopt variant from another FXVariant& adopt(FXVariant& other); /// Return value of object member FXVariant& at(const FXchar* key); /// Return value of object member const FXVariant& at(const FXchar* key) const; /// Return value of object member FXVariant& operator[](const FXchar* key){ return at(key); } /// Return value of object member const FXVariant& operator[](const FXchar* key) const { return at(key); } /// Return value of object member FXVariant& at(const FXString& key); /// Return value of object member const FXVariant& at(const FXString& key) const; /// Return value of object member FXVariant& operator[](const FXString& key){ return at(key); } /// Return value of object member const FXVariant& operator[](const FXString& key) const { return at(key); } /// Return value of array member FXVariant& at(FXival idx); /// Return value of array member const FXVariant& at(FXival idx) const; /// Return value of array member FXVariant& operator[](FXint idx){ return at(idx); } const FXVariant& operator[](FXint idx) const { return at(idx); } /// Return value of array member FXVariant& operator[](FXival idx){ return at(idx); } const FXVariant& operator[](FXival idx) const { return at(idx); } /// Check if key is mapped FXbool has(const FXchar* key) const; /// Check if key is mapped FXbool has(const FXString& key) const { return has(key.text()); } /// Return the value of the variant as a pointer; variant type MUST be PointerType FXptr& asPtr(){ return value.p; } /// Return the value of the variant as a pointer; variant type MUST be PointerType const FXptr& asPtr() const { return value.p; } /// Return the value of the variant as a long; variant type MUST be LongType FXlong& asLong(){ return value.i; } /// Return the value of the variant as a long; variant type MUST be LongType const FXlong& asLong() const { return value.i; } /// Return the value of the variant as an unsigned long; variant type MUST be ULongType FXulong& asULong(){ return value.u; } /// Return the value of the variant as an unsigned long; variant type MUST be ULongType const FXulong& asULong() const { return value.u; } /// Return the value of the variant as a double; variant type MUST be DoubleType FXdouble& asDouble(){ return value.d; } /// Return the value of the variant as a double; variant type MUST be DoubleType const FXdouble& asDouble() const { return value.d; } /// Return the value of the variant as a char pointer; variant type MUST be StringType const FXchar* asChars() const { return value.s; } /// Return the value of the variant as a string-reference; variant type MUST be StringType FXString& asString(){ return *reinterpret_cast(&value.p); } /// Return the value of the variant as a const string-reference; variant type MUST be StringType const FXString& asString() const { return *reinterpret_cast(&value.p); } /// Return the value of the variant as an array-reference; variant type MUST be ArrayType FXVariantArray& asArray(){ return *reinterpret_cast(&value.p); } /// Return the value of the variant as a const array-reference; variant type MUST be ArrayType const FXVariantArray& asArray() const { return *reinterpret_cast(&value.p); } /// Return the value of the variant as an map-reference; variant type MUST be MapType FXVariantMap& asMap(){ return *reinterpret_cast(&value.p); } /// Return the value of the variant as a const map-reference; variant type MUST be MapType const FXVariantMap& asMap() const { return *reinterpret_cast(&value.p); } /// Remove variant at key from map FXbool remove(const FXchar* key); /// Remove variant at key from map FXbool remove(const FXString& key){ return remove(key.text()); } /// Erase variant at idx from array FXbool erase(FXival idx); /// Clear the data FXbool clear(); /// Default constant variant static const FXVariant null; /// Destroy ~FXVariant(); }; } #endif