TurtleBrains  0.3.5
High quality, portable, C++ framework for rapid 2D game development.
tb_dynamic_structure.hpp
1 
9 #ifndef TurtleBrains_DynamicStructure_hpp
10 #define TurtleBrains_DynamicStructure_hpp
11 
12 #include <turtle_brains/core/tb_string.hpp>
13 #include <turtle_brains/core/tb_types.hpp>
14 
15 #include <cmath>
16 #include <vector>
17 #include <map>
18 #include <string>
19 #include <limits>
20 #include <initializer_list>
21 
22 namespace TurtleBrains
23 {
24  namespace Core
25  {
26  class DynamicStructure;
27 
28  //Ultimately these would be in FileUtilities and specializations of the ReadBinary/WriteBinary template functions.
29  //That said trying to declare a friend of a template specialization is bonkers.
30  void WriteBinary(const tbCore::DynamicStructure& data, std::ostream& output);
31  tbCore::DynamicStructure ReadBinary(std::istream& input);
32 
38  {
39  public:
43  typedef std::vector<DynamicStructure> ArrayContainer;
44 
48  typedef std::map<tbCore::tbString, DynamicStructure> StructureContainer;
49 
53  DynamicStructure(void);
54 
59  DynamicStructure(const int& integerValue);
60  DynamicStructure(const tbCore::int64& integerValue);
61  DynamicStructure(const size_t& intergerValue);
62 
67  DynamicStructure(const float& floatValue);
68 
73  DynamicStructure(const bool& booleanValue);
74 
79  DynamicStructure(const tbCore::tbString& stringValue);
80 
85  DynamicStructure(const char* stringValue);
86 
98  template<typename Type> DynamicStructure(std::initializer_list<const Type> arguments) :
99  mValueType(kNilType),
100  mInteger(0)
101  {
102  for (auto value : arguments)
103  {
104  PushValue(value);
105  }
106  }
107 
121  DynamicStructure(std::initializer_list<std::pair<const tbCore::tbString, const DynamicStructure>> arguments);
122 
127  DynamicStructure(const DynamicStructure& other);
128 
130 
136 
138 
139 
145  ~DynamicStructure(void);
146 
147 
154  bool IsNil(void) const;
155 
159  bool IsArray(void) const;
160 
165  bool IsStructure(void) const;
166 
170  bool IsInteger(void) const;
171 
175  bool IsFloat(void) const;
176 
180  bool IsBoolean(void) const;
181 
185  bool IsString(void) const;
186 
187 
196  tbCore::int64 AsInteger(bool implicitConversion = kImplicitConversions) const;
197 
216  // template <typename Type> typename std::enable_if<std::is_unsigned<Type>::value, Type>::type
217  // AsRangedInteger(const tbCore::tbString& errorMessage,
218  // const Type minimumValue = MinimumValue<Type>(), const Type maximumValue = MaximumValue<Type>(),
219  // bool implicitConversion = kImplicitConversions) const
220  // {
221  // const tbCore::int64 intValue = AsInteger(implicitConversion);
222 
223  // tb_error_if(std::is_unsigned<Type>::value && intValue < 0, "%s (Expected _value(%d) to be greater than 0 for unsigned ranges.",
224  // errorMessage.c_str(), intValue);
225 
226  // //int32 intValue = -1 : 0x0001FFFF //131k
227 
228  // //uint16 min 0 : 0x00000000
229  // //uint16 max 65 : 0x0000FFFF
230 
231 
232  // //int64 value 0x00000000-FFFFFFFF
233  // //int64 min 0x00000000-00000000
234  // //int64 max 0x00000000-FFFFFFFF
235 
236  // //int32 to uint32 65xxx : 0xFFFFFFFF
237 
238 
239  // tb_error_if(static_cast<Type>(intValue) < (minimumValue) || static_cast<Type>(intValue) > (maximumValue),
240  // "%s (Expected: %d <= _value(%d)_ <= %d", errorMessage.c_str(), minimumValue, intValue, maximumValue);
241  // return static_cast<Type>(intValue);
242  // }
243  template <typename Type> Type AsRangedInteger(const tbCore::tbString& errorMessage = "Out of Range",
244  const Type minimumValue = std::numeric_limits<Type>::min(), const Type maximumValue = std::numeric_limits<Type>::max(),
245  bool implicitConversion = kImplicitConversions) const
246  {
247  const tbCore::int64 intValue = AsInteger(implicitConversion);
248 
249  if (std::is_unsigned<Type>::value)
250  { //If type is unsigned, ensure it is not less than 0, then cast to an unsigned to compare vs other unsigned values.
251  tb_error_if(intValue < 0, "%s (Expected _value(%d) to be greater than 0 for unsigned ranges.",
252  errorMessage.c_str(), intValue);
253  tb_error_if(minimumValue < 0, "tbExternalError: Expected minimumValue of unsigned type to be greater than equal to 0.");
254  tb_error_if(maximumValue < 0, "tbExternalError: Expected maximumValue of unsigned type to be greater than equal to 0.");
255  tb_error_if(static_cast<uint64>(intValue) < static_cast<uint64>(minimumValue) || static_cast<uint64>(intValue) > static_cast<uint64>(maximumValue),
256  "%s (Expected: %d <= _value(%d)_ <= %d", errorMessage.c_str(), minimumValue, intValue, maximumValue);
257  }
258  else
259  {
260  tb_error_if(intValue < static_cast<int64>(minimumValue) ||intValue > static_cast<int64>(maximumValue),
261  "%s (Expected: %d <= _value(%d)_ <= %d", errorMessage.c_str(), minimumValue, intValue, maximumValue);
262  }
263 
264  return static_cast<Type>(intValue);
265  }
266 
267  template <typename Type> Type AsRangedIntegerWithDefault(const tbCore::tbString& errorMessage, const Type& defaultValue,
268  const Type minimumValue = std::numeric_limits<Type>::min(), const Type maximumValue = std::numeric_limits<Type>::max(),
269  bool implicitConversion = kImplicitConversions) const
270  {
271  if (true == IsNil() || (false == implicitConversion && false == IsInteger()))
272  {
273  return defaultValue;
274  }
275 
276  return AsRangedInteger(errorMessage, minimumValue, maximumValue, implicitConversion);
277  }
278 
287  float AsFloat(bool implicitConversion = kImplicitConversions) const;
288 
297  bool AsBoolean(bool implicitConversion = kImplicitConversions) const;
298 
307  tbCore::tbString AsString(bool implicitConversion = kImplicitConversions) const;
308 
309  //
310  // TODO: TurtleBrains: Planning: Do we want to support this? If so implement and document.
311  // @note Cannot implicitly convert to a string, will assert if type is not a string.
312  //
313  //const tbCore::tbString& AsStringRef(void) const;
314 
315 
329  tbCore::int64 AsIntegerWithDefault(const tbCore::int64& defaultValue, bool implicitConversion = true) const;
330 
348  template <typename Type> Type AsRangedIntegerWithDefault(const Type& defaultValue, const tbCore::tbString& errorMessage,
349  const Type minimumValue = std::numeric_limits<Type>::min(), const Type maximumValue = std::numeric_limits<Type>::max()) const
350  {
351  const tbCore::int64 intValue = AsIntegerWithDefault(defaultValue);
352 
353  if (std::is_unsigned<Type>::value)
354  { //If type is unsigned, ensure it is not less than 0, then cast to an unsigned to compare vs other unsigned values.
355  tb_error_if(std::is_unsigned<Type>::value && intValue < 0, "%s (Expected _value(%d) to be greater than 0 for unsigned ranges.",
356  errorMessage.c_str(), intValue);
357  tb_error_if(static_cast<uint64>(intValue) < minimumValue || static_cast<uint64>(intValue) > maximumValue,
358  "%s (Expected: %d <= _value(%d)_ <= %d", errorMessage.c_str(), minimumValue, intValue, maximumValue);
359  }
360  else
361  {
362  tb_error_if(intValue < static_cast<int64>(minimumValue) ||intValue > static_cast<int64>(maximumValue),
363  "%s (Expected: %d <= _value(%d)_ <= %d", errorMessage.c_str(), minimumValue, intValue, maximumValue);
364  }
365 
366  return static_cast<Type>(intValue);
367  }
368 
382  float AsFloatWithDefault(const float defaultValue, bool implicitConversion = true) const;
383 
397  bool AsBooleanWithDefault(const bool defaultValue, bool implicitConversion = true) const;
398 
412  tbCore::tbString AsStringWithDefault(const tbCore::tbString& defaultValue, bool implicitConversion = true) const;
413 
414 
424  void SetValue(const int& integerValue, bool implicitTypeChange = kImplicitTypeChange);
425  void SetValue(const tbCore::int64& integerValue, bool implicitTypeChange = kImplicitTypeChange);
426 
436  void SetValue(const float& floatValue, bool implicitTypeChange = kImplicitTypeChange);
437 
447  void SetValue(const bool& booleanValue, bool implicitTypeChange = kImplicitTypeChange);
448 
458  void SetValue(const tbCore::tbString& stringValue, bool implicitTypeChange = kImplicitTypeChange);
459 
460  //-------------------------------------------------------------------------------------------------------//
461  // Input and Output
462  //-------------------------------------------------------------------------------------------------------//
463 
467  //void WriteBinary(std::ofstream& outputFile) const;
468 
472  //void ReadBinary(std::ifstream& inputFile);
473 
474  friend void WriteBinary(const tbCore::DynamicStructure& data, std::ostream& output);
475  friend tbCore::DynamicStructure ReadBinary(std::istream& input);
476 
477  //-------------------------------------------------------------------------------------------------------//
478  // Ignore the mess of private API:
479  //-------------------------------------------------------------------------------------------------------//
480  private:
481  const tbCore::DynamicStructure& LookupByNameOrIndex(tbCore::uint64 index) const;
482  tbCore::DynamicStructure& LookupByNameOrIndex(tbCore::uint64 index);
483  const tbCore::DynamicStructure& LookupByNameOrIndex(const tbCore::tbString& memberName) const;
484  tbCore::DynamicStructure& LookupByNameOrIndex(const tbCore::tbString& memberName);
485  const tbCore::DynamicStructure& LookupByNameOrIndex(const char* memberName) const;
486  tbCore::DynamicStructure& LookupByNameOrIndex(const char* memberName);
487 
488  public:
492  template<typename Type> const DynamicStructure& operator[](const Type& nameOrIndex) const { return LookupByNameOrIndex(nameOrIndex); }
493 
497  template<typename Type> DynamicStructure& operator[](const Type& nameOrIndex) { return LookupByNameOrIndex(nameOrIndex); }
498 
499  //-------------------------------------------------------------------------------------------------------//
500  // Used ONLY for Array Values. Type must be kArrayType or kNilType to PushValue
501  //-------------------------------------------------------------------------------------------------------//
502 
513 
524  const DynamicStructure& GetValue(const tbCore::uint64& arrayIndex) const;
525 
536  DynamicStructure& GetValue(const tbCore::uint64& arrayIndex);
537 
545  size_t ArraySize(void) const;
546 
551  size_t size(void) const;
552 
559  ArrayContainer::const_iterator BeginArray(void) const;
560 
564  ArrayContainer::iterator BeginArray(void);
565 
569  ArrayContainer::const_iterator begin(void) const;
570 
574  ArrayContainer::iterator begin(void);
575 
582  ArrayContainer::const_iterator EndArray(void) const;
583 
587  ArrayContainer::iterator EndArray(void);
588 
592  ArrayContainer::const_iterator end(void) const;
593 
597  ArrayContainer::iterator end(void);
598 
608  const ArrayContainer& AsArray(void) const;
609 
613  ArrayContainer& AsArray(void);
614 
615  //-------------------------------------------------------------------------------------------------------//
616  // Used ONLY for Structure Values. Type must be kStructureType or kNilType to AddMember
617  //-------------------------------------------------------------------------------------------------------//
618 
629  DynamicStructure& AddMember(const tbCore::tbString& memberName, const DynamicStructure& memberValue);
630 
641  DynamicStructure& SetMember(const tbCore::tbString& memberName, const DynamicStructure& memberValue);
642 
652  const DynamicStructure& GetMember(const tbCore::tbString& memberName) const;
653 
657  DynamicStructure& GetMember(const tbCore::tbString& memberName);
658 
663  size_t StructureSize(void) const;
664 
669  StructureContainer::const_iterator BeginStructure(void) const;
670 
674  StructureContainer::iterator BeginStructure(void);
675 
680  StructureContainer::const_iterator EndStructure(void) const;
681 
685  StructureContainer::iterator EndStructure(void);
686 
702  const StructureContainer& AsStructure(void) const;
703 
707  StructureContainer& AsStructure(void);
708 
709  //TODO: TIM: Implementation: (Test) Add a way to iterate over all Members in a structure.
710 
711  //-------------------------------------------------------------------------------------------------------//
712  // Used ONLY for Structure or Array Values.
713  //-------------------------------------------------------------------------------------------------------//
714 
715  //Acceptable Inputs:
716  // "engine.pistons[0].isDamaged"
717  //const DynamicStructure& FromPath(const tbCore::tbString& path) const;
718 
722  explicit operator tbCore::int64() const { return AsInteger(true); }
723 
724  explicit operator int() const { return AsRangedInteger<int>(); }
725 
729  explicit operator float() const { return AsFloat(true); }
730 
734  explicit operator bool() const { return AsBoolean(true); }
735 
739  explicit operator tbCore::tbString() const { return AsString(true); }
740 
748  bool operator==(const DynamicStructure& rightSide) const;
749 
757  bool operator!=(const DynamicStructure& rightSide) const;
758 
759  private:
763  void SetToNil(void);
764 
768  tbCore::int64 ConvertToInteger(void) const;
769 
773  float ConvertToFloat(void) const;
774 
778  bool ConvertToBoolean(void) const;
779 
783  tbCore::tbString ConvertToString(void) const;
784 
788  enum DynamicStructureValueType : tbCore::uint8
789  {
790  kNilType,
791 
792  kIntegerType,
793  kFloatType,
794  kBooleanType,
795  kStringType,
796 
797  kArrayType,
798  kStructureType,
799  };
800 
804  DynamicStructureValueType mValueType;
805 
806  union
807  { //Unnamed anonymous union so DynamicStrucure contains the contents as its own members, "this->mRawBytes".
808  char mRawBytes[8]; //Reserve 64-bits for whatever types follow.
809  tbCore::int64 mInteger;
810  bool mBoolean;
811  float mFloat;
812 
813  tbCore::tbString* mString;
814  ArrayContainer* mArray;
815  StructureContainer* mStructure;
816  };
817 
818  public:
823  static const unsigned int kInvalidSize;
824  static const bool kImplicitConversions;
825  static const bool kImplicitTypeChange;
826  static const float kFloatElipson;
827  };
828 
829  inline const tbCore::DynamicStructure& tbCore::DynamicStructure::LookupByNameOrIndex(tbCore::uint64 arrayIndex) const { return GetValue(arrayIndex); }
830  inline tbCore::DynamicStructure& tbCore::DynamicStructure::LookupByNameOrIndex(tbCore::uint64 arrayIndex) { return GetValue(arrayIndex); }
831  inline const tbCore::DynamicStructure& tbCore::DynamicStructure::LookupByNameOrIndex(const tbCore::tbString& memberName) const { return GetMember(memberName); }
832  inline tbCore::DynamicStructure& tbCore::DynamicStructure::LookupByNameOrIndex(const tbCore::tbString& memberName) { return GetMember(memberName); }
833  inline const tbCore::DynamicStructure& tbCore::DynamicStructure::LookupByNameOrIndex(const char* memberName) const { return GetMember(memberName); }
834  inline tbCore::DynamicStructure& tbCore::DynamicStructure::LookupByNameOrIndex(const char* memberName) { return GetMember(memberName); }
835 
839  tbCore::tbString ToJsonString(const tbCore::DynamicStructure& data, bool prettyJson);
840 
842 
843  std::ostream& operator<<(std::ostream& outputStream, const DynamicStructure& data);
844 
845  //This is actually not _that_ trivial, at least not with how we have implemented the operator<<. So we either
846  //changed that format to make this easier, or ignore doing this for now. You can always save ToJsonString and
847  //then use tbCore::ParseJson() to get back.
848  //std::istream& operator>>(std::istream& inputStream, DynamicStructure& data);
849 
850  /* Overloads to make the DynamicStructure behave like a built in Integer */
851  inline bool operator==(const DynamicStructure& leftSide, const int& rightSide) { return (leftSide.AsInteger() == rightSide) ? true : false; }
852  inline bool operator==(const int& leftSide, const DynamicStructure& rightSide) { return (rightSide.AsInteger() == leftSide) ? true : false; }
853  inline bool operator!=(const DynamicStructure& leftSide, const int& rightSide) { return (leftSide.AsInteger() != rightSide) ? true : false; }
854  inline bool operator!=(const int& leftSide, const DynamicStructure& rightSide) { return (rightSide.AsInteger() != leftSide) ? true : false; }
855 
856  inline bool operator==(const DynamicStructure& leftSide, const tbCore::int64& rightSide) { return (leftSide.AsInteger() == rightSide) ? true : false; }
857  inline bool operator==(const tbCore::int64& leftSide, const DynamicStructure& rightSide) { return (rightSide.AsInteger() == leftSide) ? true : false; }
858  inline bool operator!=(const DynamicStructure& leftSide, const tbCore::int64& rightSide) { return (leftSide.AsInteger() != rightSide) ? true : false; }
859  inline bool operator!=(const tbCore::int64& leftSide, const DynamicStructure& rightSide) { return (rightSide.AsInteger() != leftSide) ? true : false; }
860 
861  inline bool operator==(const DynamicStructure& leftSide, const float& rightSide) { return (fabs(leftSide.AsFloat() - rightSide) <= DynamicStructure::kFloatElipson) ? true : false; }
862  inline bool operator==(const float& leftSide, const DynamicStructure& rightSide) { return (fabs(rightSide.AsFloat() - leftSide) <= DynamicStructure::kFloatElipson) ? true : false; }
863  inline bool operator!=(const DynamicStructure& leftSide, const float& rightSide) { return (fabs(leftSide.AsFloat() - rightSide) > DynamicStructure::kFloatElipson) ? true : false; }
864  inline bool operator!=(const float& leftSide, const DynamicStructure& rightSide) { return (fabs(rightSide.AsFloat() - leftSide) > DynamicStructure::kFloatElipson) ? true : false; }
865 
866  inline bool operator==(const DynamicStructure& leftSide, const bool& rightSide) { return (leftSide.AsBoolean() == rightSide) ? true : false; }
867  inline bool operator==(const bool& leftSide, const DynamicStructure& rightSide) { return (rightSide.AsBoolean() == leftSide) ? true : false; }
868  inline bool operator!=(const DynamicStructure& leftSide, const bool& rightSide) { return (leftSide.AsBoolean() != rightSide) ? true : false; }
869  inline bool operator!=(const bool& leftSide, const DynamicStructure& rightSide) { return (rightSide.AsBoolean() != leftSide) ? true : false; }
870 
871  inline bool operator==(const DynamicStructure& leftSide, const tbCore::tbString& rightSide) { return (leftSide.AsString() == rightSide) ? true : false; }
872  inline bool operator==(const tbCore::tbString& leftSide, const DynamicStructure& rightSide) { return (rightSide.AsString() == leftSide) ? true : false; }
873  inline bool operator!=(const DynamicStructure& leftSide, const tbCore::tbString& rightSide) { return (leftSide.AsString() != rightSide) ? true : false; }
874  inline bool operator!=(const tbCore::tbString& leftSide, const DynamicStructure& rightSide) { return (rightSide.AsString() != leftSide) ? true : false; }
875 
877 
878  }; /* namespace Core */
879 }; /* namespace TurtleBrains */
880 
881 namespace tbCore = TurtleBrains::Core;
882 
883 #endif /* TurtleBrains_DynamicStructure_hpp */
int64_t int64
Signed integer with a size of 64 bits. Supports values from -(2^63) to (2^63 - 1).
Definition: tb_types.hpp:29
tbCore::tbString ToJsonString(const tbCore::DynamicStructure &data, bool prettyJson)
ArrayContainer::const_iterator BeginArray(void) const
const DynamicStructure & GetMember(const tbCore::tbString &memberName) const
tbCore::tbString AsStringWithDefault(const tbCore::tbString &defaultValue, bool implicitConversion=true) const
tbCore::int64 AsIntegerWithDefault(const tbCore::int64 &defaultValue, bool implicitConversion=true) const
DynamicStructure & PushValue(const DynamicStructure &value)
static const bool kImplicitConversions
Definition: tb_dynamic_structure.hpp:824
Type AsRangedIntegerWithDefault(const Type &defaultValue, const tbCore::tbString &errorMessage, const Type minimumValue=std::numeric_limits< Type >::min(), const Type maximumValue=std::numeric_limits< Type >::max()) const
Definition: tb_dynamic_structure.hpp:348
static const DynamicStructure kNullValue
Definition: tb_dynamic_structure.hpp:819
ArrayContainer::const_iterator begin(void) const
tbCore::tbString AsString(bool implicitConversion=kImplicitConversions) const
StructureContainer::const_iterator EndStructure(void) const
static const float kFloatElipson
Definition: tb_dynamic_structure.hpp:826
Here is some information about the primary namespace.
Definition: tb_application_dialog.hpp:21
float AsFloat(bool implicitConversion=kImplicitConversions) const
static const tbCore::tbString kTrueAsString
Definition: tb_dynamic_structure.hpp:821
static const unsigned int kInvalidSize
Definition: tb_dynamic_structure.hpp:823
uint64_t uint64
Unsigned integer with a size of 64 bits, Supports values from 0 to (2^64 - 1).
Definition: tb_types.hpp:30
bool operator!=(const DynamicStructure &rightSide) const
friend void WriteBinary(const tbCore::DynamicStructure &data, std::ostream &output)
uint8_t uint8
Unsigned integer with a size of 8 bits. Supports values from 0 to 255.
Definition: tb_types.hpp:23
const StructureContainer & AsStructure(void) const
ArrayContainer::const_iterator EndArray(void) const
Type AsRangedInteger(const tbCore::tbString &errorMessage="Out of Range", const Type minimumValue=std::numeric_limits< Type >::min(), const Type maximumValue=std::numeric_limits< Type >::max(), bool implicitConversion=kImplicitConversions) const
Definition: tb_dynamic_structure.hpp:243
static const tbCore::tbString kNullAsString
Definition: tb_dynamic_structure.hpp:820
bool AsBooleanWithDefault(const bool defaultValue, bool implicitConversion=true) const
Definition: tb_dynamic_structure.hpp:37
const DynamicStructure & GetValue(const tbCore::uint64 &arrayIndex) const
float AsFloatWithDefault(const float defaultValue, bool implicitConversion=true) const
void WriteBinary(const tbCore::DynamicStructure &data, std::ostream &output)
std::map< tbCore::tbString, DynamicStructure > StructureContainer
Definition: tb_dynamic_structure.hpp:48
DynamicStructure(std::initializer_list< const Type > arguments)
Definition: tb_dynamic_structure.hpp:98
static const tbCore::tbString kFalseAsString
Definition: tb_dynamic_structure.hpp:822
bool operator==(const DynamicStructure &rightSide) const
bool AsBoolean(bool implicitConversion=kImplicitConversions) const
std::vector< DynamicStructure > ArrayContainer
Definition: tb_dynamic_structure.hpp:43
StructureContainer::const_iterator BeginStructure(void) const
DynamicStructure & AddMember(const tbCore::tbString &memberName, const DynamicStructure &memberValue)
void SetValue(const int &integerValue, bool implicitTypeChange=kImplicitTypeChange)
Contains core functionality for each component of the API.
Definition: tb_debug_logger.hpp:88
tbCore::int64 AsInteger(bool implicitConversion=kImplicitConversions) const
ArrayContainer::const_iterator end(void) const
#define tb_error_if(errorTest, message,...)
Definition: tb_error.hpp:42
std::string tbString
Definition: tb_string.hpp:335
DynamicStructure & operator=(const DynamicStructure &other)
const ArrayContainer & AsArray(void) const
static const bool kImplicitTypeChange
Definition: tb_dynamic_structure.hpp:825
DynamicStructure & SetMember(const tbCore::tbString &memberName, const DynamicStructure &memberValue)