├── CMakeLists.txt ├── src ├── CMakeLists.txt ├── constructor.cpp ├── constructor.h ├── enum.cpp ├── enum.h ├── exception.h ├── field.cpp ├── field.h ├── method.cpp ├── method.h ├── param.cpp ├── param.h ├── qualified_type.cpp ├── qualified_type.h ├── reflection.h ├── string_helper.h ├── type.cpp ├── type.h └── utils.h └── test_json ├── CMakeLists.txt ├── json11.cpp ├── json11.hpp └── test_json.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(reflection) 2 | 3 | set(HOME ${reflection_SOURCE_DIR}) 4 | 5 | #if(CMAKE_COMPILER_IS_GNUCXX) 6 | add_definitions("-std=c++11") 7 | #endif() 8 | 9 | add_subdirectory(src) 10 | add_subdirectory(test_json) 11 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(reflection_lib) 2 | 3 | include_directories( ./ ) 4 | 5 | set(SRC 6 | constructor.cpp 7 | constructor.h 8 | enum.cpp 9 | enum.h 10 | exception.h 11 | field.cpp 12 | field.h 13 | method.cpp 14 | method.h 15 | param.cpp 16 | param.h 17 | reflection.h 18 | type.cpp 19 | type.h 20 | utils.h 21 | string_helper.h 22 | qualified_type.cpp 23 | qualified_type.h 24 | ) 25 | 26 | add_library(lib ${SRC}) 27 | set_target_properties(lib PROPERTIES OUTPUT_NAME "reflection") 28 | 29 | set(LIBRARY_OUTPUT_PATH ${HOME}/lib) 30 | -------------------------------------------------------------------------------- /src/constructor.cpp: -------------------------------------------------------------------------------- 1 | #include "constructor.h" 2 | #include "type.h" 3 | 4 | std::string Constructor::GetDescription() const{ 5 | std::stringstream ss; 6 | ss << type->GetName() << "("; 7 | for (int i = 0, n = paramTypes.size(); i paramTypes; 14 | 15 | Constructor(const Type* type, const std::vector& paramTypes){ 16 | this->type = type; 17 | this->paramTypes = paramTypes; 18 | } 19 | 20 | public: 21 | int GetParamCount() const{ 22 | return paramTypes.size(); 23 | } 24 | 25 | const std::vector GetParamTypes() const{ 26 | return paramTypes; 27 | } 28 | 29 | const Type* GetType() const{ 30 | return type; 31 | } 32 | 33 | std::string GetDescription() const; 34 | 35 | virtual Any Invoke() const{ 36 | THROW_EXCEPTION(InvalidArguments, "tried to invoke constructor '" + GetDescription() + "' with no arguments"); 37 | } 38 | 39 | virtual Any Invoke(Any p1) const{ 40 | THROW_EXCEPTION(InvalidArguments, "tried to invoke constructor '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ")"); 41 | } 42 | 43 | virtual Any Invoke(Any p1, Any p2) const{ 44 | THROW_EXCEPTION(InvalidArguments, "tried to invoke constructor '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ")"); 45 | } 46 | 47 | virtual Any Invoke(Any p1, Any p2, Any p3) const{ 48 | THROW_EXCEPTION(InvalidArguments, "tried to invoke constructor '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ")"); 49 | } 50 | 51 | virtual Any Invoke(Any p1, Any p2, Any p3, Any p4) const{ 52 | THROW_EXCEPTION(InvalidArguments, "tried to invoke constructor '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ", " + p4.GetType().ToString() + ")"); 53 | } 54 | 55 | virtual Any Invoke(Any p1, Any p2, Any p3, Any p4, Any p5) const{ 56 | THROW_EXCEPTION(InvalidArguments, "tried to invoke constructor '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ", " + p4.GetType().ToString() + ", " + p5.GetType().ToString() + ")"); 57 | } 58 | 59 | virtual Any Invoke(Any p1, Any p2, Any p3, Any p4, Any p5, Any p6) const{ 60 | THROW_EXCEPTION(InvalidArguments, "tried to invoke constructor '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ", " + p4.GetType().ToString() + ", " + p5.GetType().ToString() + ", " + p6.GetType().ToString() + ")"); 61 | } 62 | 63 | virtual Any Invoke(Any p1, Any p2, Any p3, Any p4, Any p5, Any p6, Any p7) const{ 64 | THROW_EXCEPTION(InvalidArguments, "tried to invoke constructor '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ", " + p4.GetType().ToString() + ", " + p5.GetType().ToString() + ", " + p6.GetType().ToString() + ", " + p7.GetType().ToString() + ")"); 65 | } 66 | 67 | virtual Any Invoke(Any p1, Any p2, Any p3, Any p4, Any p5, Any p6, Any p7, Any p8) const{ 68 | THROW_EXCEPTION(InvalidArguments, "tried to invoke constructor '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ", " + p4.GetType().ToString() + ", " + p5.GetType().ToString() + ", " + p6.GetType().ToString() + ", " + p7.GetType().ToString() + ", " + p8.GetType().ToString() + ")"); 69 | } 70 | }; 71 | 72 | template 73 | class ConstructorImpl : public Constructor{ 74 | private: 75 | const Type* type; 76 | 77 | public: 78 | ConstructorImpl() 79 | : Constructor(typeof(T), { GetQualifiedType::Value() ... }){ 80 | static_assert(std::is_constructible::value, "tried to register an undeclared constructor"); 81 | } 82 | 83 | virtual Any Invoke(typename AsType::Value... params) const override{ 84 | return (Any)new T(std::forward((Args)params)...); 85 | } 86 | }; 87 | 88 | // doing partial specialization here to avoid a bug on Visual Studio which is fixed on Visual Studio 2015 89 | #if defined(_MSC_VER) && _MSC_VER <= 1800 90 | 91 | template 92 | class ConstructorImpl : public Constructor{ 93 | private: 94 | const Type* type; 95 | 96 | public: 97 | ConstructorImpl() 98 | : Constructor(typeof(T), { }){ 99 | static_assert(std::is_constructible::value, "tried to register an undeclared constructor"); 100 | } 101 | 102 | virtual Any Invoke() const override{ 103 | return (Any)new T(); 104 | } 105 | }; 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /src/enum.cpp: -------------------------------------------------------------------------------- 1 | #include "enum.h" 2 | #include "type.h" 3 | #include "string_helper.h" 4 | #include "exception.h" 5 | 6 | const Type* Enum::GetEnum(const std::string& enumTypeName, bool throwIfNotFound){ 7 | const Type* enumType = Type::GetType(enumTypeName); 8 | 9 | if (throwIfNotFound){ 10 | if (enumType == nullptr){ 11 | THROW_EXCEPTION(EnumNotFound, "enum '" + enumTypeName + "' not found"); 12 | } 13 | else if (!enumType->IsEnum()){ 14 | THROW_EXCEPTION(NotAnEnum, "'" + enumTypeName + "' is not an enum type"); 15 | } 16 | } 17 | 18 | if (enumType != nullptr && !enumType->IsEnum()){ 19 | return nullptr; 20 | } 21 | 22 | return enumType; 23 | } 24 | 25 | int64_t Enum::GetValue(const Type* enumType, const std::string& enumName){ 26 | if (!enumType->IsEnum()) 27 | THROW_EXCEPTION(NotAnEnum, "'" + enumType->GetName() + "' is not an enum type"); 28 | 29 | auto& map = Enums()[enumType]; 30 | if (map.find(enumName) == map.end()) 31 | THROW_EXCEPTION(EnumNameNotFound, "enum '" + enumType->GetName() + "' has no member named '" + enumName + "'"); 32 | 33 | return map[enumName]; 34 | } 35 | 36 | std::string Enum::GetName(const Type* enumType, int64_t value){ 37 | if (!enumType->IsEnum()) 38 | THROW_EXCEPTION(NotAnEnum, "'" + enumType->GetName() + "' is not an enum type"); 39 | 40 | auto& map = Enums2()[enumType]; 41 | if (map.find(value) == map.end()) 42 | THROW_EXCEPTION(EnumValueNotFound, "enum '" + enumType->GetName() + "' has no member valued '" + std::to_string(value) + "'"); 43 | 44 | return map[value]; 45 | } 46 | 47 | std::vector Enum::GetValues(const Type* enumType){ 48 | if (!enumType->IsEnum()) 49 | THROW_EXCEPTION(NotAnEnum, "'" + enumType->GetName() + "' is not an enum type"); 50 | 51 | std::vector values; 52 | for (auto& i : Enums()[enumType]){ 53 | values.push_back(i.second); 54 | } 55 | 56 | return values; 57 | } 58 | 59 | std::vector Enum::GetNames(const Type* enumType){ 60 | if (!enumType->IsEnum()) 61 | THROW_EXCEPTION(NotAnEnum, "'" + enumType->GetName() + "' is not an enum type"); 62 | 63 | std::vector names; 64 | for (auto& i : Enums()[enumType]){ 65 | names.push_back(i.first); 66 | } 67 | return names; 68 | } 69 | 70 | const Type* Enum::Register(const std::string& name, const std::string& values, const Type* underlyingType){ 71 | auto items = StringHelper::Split(StringHelper::RemoveSpaces(values), ','); 72 | std::unordered_map map; 73 | const Type* type = Type::RegisterEnum(new Type, name, underlyingType); 74 | int num = 0; 75 | for (auto& i : items){ 76 | if ((int)i.find('=') >= 0){ 77 | auto kv = StringHelper::Split(i, '='); 78 | num = atoi(kv[1].c_str()); 79 | map.insert(std::make_pair(kv[0], num)); 80 | } 81 | else{ 82 | map.insert(std::make_pair(i, num)); 83 | } 84 | num++; 85 | } 86 | 87 | std::unordered_map map2; 88 | for (auto& i : map){ 89 | map2.insert(std::make_pair(i.second, i.first)); 90 | } 91 | Enums().insert(std::make_pair(type, map)); 92 | Enums2().insert(std::make_pair(type, map2)); 93 | 94 | return type; 95 | } 96 | -------------------------------------------------------------------------------- /src/enum.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils.h" 4 | #include "type.h" 5 | #include "constructor.h" 6 | 7 | class Enum{ 8 | private: 9 | static std::unordered_map>& Enums(){ 10 | static std::unordered_map> enums; 11 | return enums; 12 | } 13 | 14 | static std::unordered_map>& Enums2(){ 15 | static std::unordered_map> enums; 16 | return enums; 17 | } 18 | 19 | public: 20 | static int64_t GetValue(const Type* enumType, const std::string& enumName); 21 | 22 | static std::string GetName(const Type* enumType, int64_t value); 23 | 24 | static const Type* GetEnum(const std::string& enumTypeName, bool throwIfNotFound = false); 25 | 26 | static std::vector GetValues(const Type* enumType); 27 | 28 | static std::vector GetNames(const Type* enumType); 29 | 30 | template 31 | static EnumClass GetValue(const std::string& enumName){ 32 | return (EnumClass)GetValue(typeof(EnumClass), enumName); 33 | } 34 | 35 | template 36 | static std::string GetName(EnumClass enumValue){ 37 | return GetName(typeof(EnumClass), (int64_t)enumValue); 38 | } 39 | 40 | template 41 | static std::vector GetValues(){ 42 | std::vector ret; 43 | for (auto i : GetValues(typeof(EnumClass))) 44 | ret.push_back((EnumClass)i); 45 | return ret; 46 | } 47 | 48 | template 49 | static std::vector GetNames(){ 50 | return GetNames(typeof(EnumClass)); 51 | } 52 | 53 | static const Type* Register(const std::string& name, const std::string& values, const Type* underlyingType); 54 | }; 55 | 56 | // macros to define a reflectable enum 57 | // define an enum like this: 58 | // 59 | // REFLECT_ENUM(Color, 60 | // Red, 61 | // Green, 62 | // Blue 63 | // ) 64 | // 65 | // and then you can use it like this: 66 | // 67 | // std::string name = Enum::GetName(Color::Red); 68 | // Color color = Enum::GetValue(name); 69 | // 70 | // or you can list all the items in the enum: 71 | // 72 | // for (auto i : Enum::GetValues()){ 73 | // std::cout << Enum::GetName(i) << " = " << (int)i << std::endl; 74 | // } 75 | // 76 | 77 | #define REFLECT_ENUM(typeName, ...) enum class typeName{ __VA_ARGS__ }; \ 78 | struct Enum_##typeName{ \ 79 | static const Type* GetType(){\ 80 | static const Type* type = Enum::Register(#typeName, #__VA_ARGS__, typeof(std::underlying_type::type)); \ 81 | return type; \ 82 | } \ 83 | }; \ 84 | template<> \ 85 | struct ReflectType{ \ 86 | static const Type* Value(){ \ 87 | return Enum_##typeName::GetType(); \ 88 | } \ 89 | }; \ 90 | static const Type* ____##typeName##_dummy = typeof(typeName); 91 | -------------------------------------------------------------------------------- /src/exception.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define THROW_EXCEPTION(name, msg) { name ex; ex.What() = msg; ex.Where() = std::string(__FILE__ " (" + std::to_string(__LINE__) + ")"); throw ex; } 6 | 7 | class Exception { 8 | protected: 9 | std::string what; 10 | std::string where; 11 | 12 | public: 13 | const std::string& What() const{ 14 | return what; 15 | } 16 | 17 | const std::string& Where() const{ 18 | return where; 19 | } 20 | 21 | std::string& What(){ 22 | return what; 23 | } 24 | 25 | std::string& Where(){ 26 | return where; 27 | } 28 | }; 29 | 30 | class NotAnEnum : public Exception{}; // throw while treating a normal type as an enum type 31 | class EnumNotFound : public Exception{}; 32 | class EnumNameNotFound : public Exception{}; 33 | class EnumValueNotFound : public Exception{}; 34 | class TypeNotFound : public Exception{}; 35 | class ConstructorNotFound : public Exception{}; 36 | class FieldNotFound : public Exception{}; 37 | class MethodNotFound : public Exception{}; 38 | class InvalidArguments : public Exception{}; 39 | class InvalidAccess : public Exception{}; 40 | class InternalError : public Exception{}; 41 | class InvalidCast : public Exception{}; 42 | class InvalidOperation : public Exception{}; 43 | class NullPointerException : public Exception{}; 44 | class AmbiguousMatched : public Exception{}; 45 | class TypeAlreadyExists : public Exception{}; 46 | class NoDefualtConstructor : public Exception{}; 47 | -------------------------------------------------------------------------------- /src/field.cpp: -------------------------------------------------------------------------------- 1 | #include "field.h" 2 | #include "type.h" 3 | 4 | std::string Field::GetDescription(bool showOwnerType) const{ 5 | std::stringstream ss; 6 | if (isStatic) ss << "static "; 7 | ss << fieldType.ToString() << " "; 8 | if (showOwnerType && ownerType) ss << ownerType->GetName() << "::"; 9 | ss << name; 10 | return ss.str(); 11 | } 12 | -------------------------------------------------------------------------------- /src/field.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils.h" 4 | #include "param.h" 5 | #include "exception.h" 6 | #include "qualified_type.h" 7 | 8 | class Field{ 9 | friend class Type; 10 | protected: 11 | std::string name; 12 | const Type* ownerType; 13 | const QualifiedType fieldType; 14 | bool isStatic; 15 | 16 | Field(const std::string& name, const Type* ownerType, const QualifiedType fieldType, bool isStatic = false) 17 | : fieldType(fieldType){ 18 | this->name = name; 19 | this->ownerType = ownerType; 20 | this->isStatic = isStatic; 21 | } 22 | 23 | public: 24 | // is it a static field; 25 | bool IsStatic() const{ 26 | return isStatic; 27 | } 28 | 29 | // whether if the field is qualified to const. 30 | bool IsReadonly() const{ 31 | return fieldType.IsConst(); 32 | } 33 | 34 | // whether if the field is a constant, which means it's qualified to 'static const'. 35 | bool IsConstant() const{ 36 | return IsStatic() && IsReadonly(); 37 | } 38 | 39 | std::string GetDescription(bool showOwnerType = true) const; 40 | 41 | // @throw InvalidAccess 42 | virtual void Set(Any obj, Any value) const{ 43 | THROW_EXCEPTION(InternalError, "unimplemented setter"); 44 | } 45 | 46 | virtual Any Get(Any obj) const{ 47 | THROW_EXCEPTION(InternalError, "unimplemented getter"); 48 | } 49 | 50 | const std::string& GetName() const{ 51 | return name; 52 | } 53 | 54 | const QualifiedType GetType() const{ 55 | return fieldType; 56 | } 57 | 58 | const Type* GetOwnerType() const{ 59 | return ownerType; 60 | } 61 | 62 | }; 63 | 64 | template 65 | class MemberField : public Field{ 66 | private: 67 | FieldType OwnerType::* field; 68 | 69 | public: 70 | MemberField(const std::string& name, FieldType OwnerType::* field) 71 | : Field(name, typeof(OwnerType), GetQualifiedType::Value()) { 72 | this->field = field; 73 | } 74 | 75 | virtual void Set(Any obj, Any value) const{ 76 | if (obj.IsNull()) THROW_EXCEPTION(NullPointerException, "null pointer of '" + ownerType->GetName() + "'"); 77 | ((OwnerType*)obj)->*field = value.Cast();//ParamCast(value); 78 | } 79 | 80 | virtual Any Get(Any obj) const{ 81 | if (obj.IsNull()) THROW_EXCEPTION(NullPointerException, "null pointer of '" + ownerType->GetName() + "'"); 82 | return (Any)((OwnerType*)obj->*field); 83 | } 84 | }; 85 | 86 | template 87 | class StaticField : public Field{ 88 | private: 89 | FieldType* field; 90 | 91 | public: 92 | StaticField(const std::string& name, FieldType* field) 93 | : Field(name, nullptr, GetQualifiedType::Value(), true) { 94 | this->field = field; 95 | } 96 | 97 | virtual void Set(Any obj, Any value) const{ 98 | *field = (FieldType)value;//ParamCast(value); 99 | } 100 | 101 | virtual Any Get(Any obj) const{ 102 | return (Any)*field; 103 | } 104 | }; 105 | 106 | template 107 | class ReadonlyField : public Field{ 108 | private: 109 | FieldType OwnerType::* field; 110 | 111 | public: 112 | ReadonlyField(const std::string& name, FieldType OwnerType::* field) 113 | : Field(name, typeof(OwnerType), GetQualifiedType::Value(), false) { 114 | this->field = field; 115 | } 116 | 117 | virtual void Set(Any obj, Any value) const{ 118 | THROW_EXCEPTION(InvalidAccess, "tried to set value on a readonly field '" + GetDescription() + "'"); 119 | } 120 | 121 | virtual Any Get(Any obj) const{ 122 | if (obj == nullptr) THROW_EXCEPTION(NullPointerException, "null pointer of '" + ownerType->GetName() + "'"); 123 | return (Any)((OwnerType*)obj->*field); 124 | } 125 | }; 126 | 127 | template 128 | class ConstField : public Field{ 129 | private: 130 | FieldType* field; 131 | 132 | public: 133 | ConstField(const std::string& name, FieldType* field) 134 | : Field(name, nullptr, GetQualifiedType::Value(), true) { 135 | this->field = field; 136 | } 137 | 138 | virtual void Set(Any obj, Any value) const{ 139 | THROW_EXCEPTION(InvalidAccess, "tried to set value on a const field '" + GetDescription() + "'"); 140 | } 141 | 142 | virtual Any Get(Any obj) const{ 143 | return (Any)*field; 144 | } 145 | }; 146 | -------------------------------------------------------------------------------- /src/method.cpp: -------------------------------------------------------------------------------- 1 | #include "method.h" 2 | #include "type.h" 3 | 4 | std::string Method::GetDescription(bool showOwnerType) const{ 5 | std::stringstream ss; 6 | if (isStatic) ss << "static "; 7 | ss << returnType.ToString() << " "; 8 | if (showOwnerType && ownerType) ss << ownerType->GetName() << "::"; 9 | ss << name << "("; 10 | for (int i = 0, n = paramTypes.size(); i paramTypes; 16 | bool isStatic; 17 | 18 | Method(const std::string& name, const Type* ownerType, const QualifiedType returnType, const std::vector& paramTypes, bool isStatic = false) 19 | : returnType(returnType){ 20 | this->name = name; 21 | this->ownerType = ownerType; 22 | this->paramTypes = paramTypes; 23 | this->isStatic = isStatic; 24 | } 25 | 26 | public: 27 | int GetParamCount() const{ 28 | return paramTypes.size(); 29 | } 30 | 31 | bool IsStatic() const{ 32 | return isStatic; 33 | } 34 | 35 | const std::vector GetParamTypes() const{ 36 | return paramTypes; 37 | } 38 | 39 | const std::string& GetName() const{ 40 | return name; 41 | } 42 | 43 | const QualifiedType GetReturnType() const{ 44 | return returnType; 45 | } 46 | 47 | const Type* GetOwnerType() const{ 48 | return ownerType; 49 | } 50 | 51 | std::string GetDescription(bool showOwnerType = true) const; 52 | 53 | virtual Any Invoke(Any obj) const{ 54 | THROW_EXCEPTION(InvalidArguments, "tried to invoke '" + GetDescription() + "' with no arguments"); 55 | } 56 | 57 | virtual Any Invoke(Any obj, Any p1) const{ 58 | THROW_EXCEPTION(InvalidArguments, "tried to invoke '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ")"); 59 | } 60 | 61 | virtual Any Invoke(Any obj, Any p1, Any p2) const{ 62 | THROW_EXCEPTION(InvalidArguments, "tried to invoke '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ")"); 63 | } 64 | 65 | virtual Any Invoke(Any obj, Any p1, Any p2, Any p3) const{ 66 | THROW_EXCEPTION(InvalidArguments, "tried to invoke '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ")"); 67 | } 68 | 69 | virtual Any Invoke(Any obj, Any p1, Any p2, Any p3, Any p4) const{ 70 | THROW_EXCEPTION(InvalidArguments, "tried to invoke '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ", " + p4.GetType().ToString() + ")"); 71 | } 72 | 73 | virtual Any Invoke(Any obj, Any p1, Any p2, Any p3, Any p4, Any p5) const{ 74 | THROW_EXCEPTION(InvalidArguments, "tried to invoke '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ", " + p4.GetType().ToString() + ", " + p5.GetType().ToString() + ")"); 75 | } 76 | 77 | virtual Any Invoke(Any obj, Any p1, Any p2, Any p3, Any p4, Any p5, Any p6) const{ 78 | THROW_EXCEPTION(InvalidArguments, "tried to invoke '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ", " + p4.GetType().ToString() + ", " + p5.GetType().ToString() + ", " + p6.GetType().ToString() + ")"); 79 | } 80 | 81 | virtual Any Invoke(Any obj, Any p1, Any p2, Any p3, Any p4, Any p5, Any p6, Any p7) const{ 82 | THROW_EXCEPTION(InvalidArguments, "tried to invoke '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ", " + p4.GetType().ToString() + ", " + p5.GetType().ToString() + ", " + p6.GetType().ToString() + ", " + p7.GetType().ToString() + ")"); 83 | } 84 | 85 | virtual Any Invoke(Any obj, Any p1, Any p2, Any p3, Any p4, Any p5, Any p6, Any p7, Any p8) const{ 86 | THROW_EXCEPTION(InvalidArguments, "tried to invoke '" + GetDescription() + "' with arguments(" + p1.GetType().ToString() + ", " + p2.GetType().ToString() + ", " + p3.GetType().ToString() + ", " + p4.GetType().ToString() + ", " + p5.GetType().ToString() + ", " + p6.GetType().ToString() + ", " + p7.GetType().ToString() + ", " + p8.GetType().ToString() + ")"); 87 | } 88 | 89 | }; 90 | 91 | template 92 | class MemberMethod : public Method{ 93 | private: 94 | typedef ReturnType(OwnerType::*FUN) (Args...); 95 | FUN fun; 96 | 97 | public: 98 | MemberMethod(const std::string& name, FUN fun) 99 | : Method(name, typeof(OwnerType), GetQualifiedType::Value(), std::vector{ GetQualifiedType::Value()... }){ 100 | this->fun = fun; 101 | } 102 | 103 | virtual Any Invoke(Any obj, typename AsType::Value... params) const override{ 104 | if (obj.IsNull()) THROW_EXCEPTION(NullPointerException, "null pointer of '" + ownerType->GetName() + "'"); 105 | return (Any)(((OwnerType*)obj)->*fun)((Args)params...);//ParamCast(params)...); 106 | } 107 | 108 | }; 109 | 110 | template 111 | class MemberMethod : public Method{ 112 | private: 113 | typedef void (OwnerType::*FUN) (Args...); 114 | FUN fun; 115 | 116 | public: 117 | MemberMethod(const std::string& name, FUN fun) 118 | : Method(name, typeof(OwnerType), typeof(void), std::vector{ GetQualifiedType::Value()... }){///* TODO */typename BaseType::Value)... }){ 119 | this->fun = fun; 120 | } 121 | 122 | virtual Any Invoke(Any obj, typename AsType::Value... params) const override{ 123 | if (obj.IsNull()) THROW_EXCEPTION(NullPointerException, "null pointer of '" + ownerType->GetName() + "'"); 124 | (((OwnerType*)obj)->*fun)((Args)params...);//ParamCast(params)...); 125 | return nullptr; 126 | } 127 | }; 128 | 129 | template 130 | class StaticMethod : public Method{ 131 | private: 132 | typedef ReturnType(*FUN) (Args...); 133 | FUN fun; 134 | 135 | public: 136 | StaticMethod(const std::string& name, FUN fun) 137 | : Method(name, nullptr, GetQualifiedType::Value(), std::vector{ GetQualifiedType::Value()... }, true){ 138 | this->fun = fun; 139 | } 140 | 141 | virtual Any Invoke(Any obj, typename AsType::Value... params) const override{ 142 | return (Any)fun((Args)params...);//ParamCast(params)...); 143 | } 144 | 145 | }; 146 | 147 | template 148 | class StaticMethod : public Method{ 149 | private: 150 | typedef void(*FUN) (Args...); 151 | FUN fun; 152 | 153 | public: 154 | StaticMethod(const std::string& name, FUN fun) 155 | : Method(name, nullptr, typeof(void), std::vector< QualifiedType> { GetQualifiedType::Value()... }, true){ 156 | this->fun = fun; 157 | } 158 | 159 | virtual Any Invoke(Any obj, typename AsType::Value... params) const override{ 160 | fun((Args)params...);//ParamCast(params)...); 161 | return nullptr; 162 | } 163 | 164 | }; 165 | 166 | // doing partial specialization here to avoid a bug on Visual Studio which is fixed on Visual Studio 2015 167 | #if defined(_MSC_VER) && _MSC_VER <= 1800 168 | 169 | template 170 | class MemberMethod : public Method{ 171 | private: 172 | typedef ReturnType(OwnerType::*FUN) (); 173 | FUN fun; 174 | 175 | public: 176 | MemberMethod(const std::string& name, FUN fun) 177 | : Method(name, typeof(OwnerType), GetQualifiedType::Value(), {}){ 178 | this->fun = fun; 179 | } 180 | 181 | virtual Any Invoke(Any obj) const override{ 182 | if (obj.IsNull()) THROW_EXCEPTION(NullPointerException, "null pointer of '" + ownerType->GetName() + "'"); 183 | return Any((((OwnerType*)obj)->*fun)()); 184 | } 185 | 186 | }; 187 | 188 | template 189 | class MemberMethod : public Method{ 190 | private: 191 | typedef void (OwnerType::*FUN) (); 192 | FUN fun; 193 | 194 | public: 195 | MemberMethod(const std::string& name, FUN fun) 196 | : Method(name, typeof(OwnerType), typeof(void), {}){ 197 | this->fun = fun; 198 | } 199 | 200 | virtual Any Invoke(Any obj) const override{ 201 | if (obj.IsNull()) THROW_EXCEPTION(NullPointerException, "null pointer of '" + ownerType->GetName() + "'"); 202 | (((OwnerType*)obj)->*fun)(); 203 | return nullptr; 204 | } 205 | }; 206 | 207 | template 208 | class StaticMethod : public Method{ 209 | private: 210 | typedef ReturnType(*FUN) (); 211 | FUN fun; 212 | 213 | public: 214 | StaticMethod(const std::string& name, FUN fun) 215 | : Method(name, nullptr, GetQualifiedType::Value(), {}, true){ 216 | this->fun = fun; 217 | } 218 | 219 | virtual Any Invoke(Any obj) const override{ 220 | return (Any)fun(); 221 | } 222 | 223 | }; 224 | 225 | template<> 226 | class StaticMethod : public Method{ 227 | private: 228 | typedef void(*FUN) (); 229 | FUN fun; 230 | 231 | public: 232 | StaticMethod(const std::string& name, FUN fun) 233 | : Method(name, nullptr, typeof(void), {}, true){ 234 | this->fun = fun; 235 | } 236 | 237 | virtual Any Invoke(Any obj) const override{ 238 | fun(); 239 | return nullptr; 240 | } 241 | 242 | }; 243 | 244 | #endif // defined(_MSC_VER) && _MSC_VER <= 1800 245 | -------------------------------------------------------------------------------- /src/param.cpp: -------------------------------------------------------------------------------- 1 | #include "param.h" 2 | #include "enum.h" 3 | 4 | std::string Any::ToString(){ 5 | if (GetType() == qualified_typeof(const char*)) return static_cast<_Holder*>(value)->data; 6 | auto t = GetType().RemoveCV(); 7 | #define TOSTR(T) if(t == qualified_typeof(T)) return std::to_string(static_cast<_Holder*>(value)->data); \ 8 | if(t == qualified_typeof(T&)) return std::to_string(static_cast<_Holder*>(value)->data); 9 | TOSTR(int8_t); 10 | TOSTR(int16_t); 11 | TOSTR(int32_t); 12 | TOSTR(int64_t); 13 | TOSTR(uint8_t); 14 | TOSTR(uint16_t); 15 | TOSTR(uint32_t); 16 | TOSTR(uint64_t); 17 | TOSTR(bool); 18 | TOSTR(float); 19 | TOSTR(double); 20 | #undef TOSTR 21 | if (t == qualified_typeof(char*)) return static_cast<_Holder*>(value)->data; 22 | if (t == qualified_typeof(std::string)) return static_cast<_Holder*>(value)->data; 23 | if (t == qualified_typeof(std::string&)) return static_cast<_Holder*>(value)->data; 24 | if (t.GetType()->IsEnum()) return Enum::GetName(t.GetType(), static_cast<_Holder*>(value)->data); 25 | 26 | return "(unknown)"; 27 | } 28 | -------------------------------------------------------------------------------- /src/param.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils.h" 4 | #include "exception.h" 5 | #include "qualified_type.h" 6 | #include "type.h" 7 | 8 | enum class TypeKind{ 9 | Fundamental, 10 | Enum, 11 | Class, 12 | Pointer, 13 | AnyPointer, 14 | Reference, 15 | RightValueReference 16 | }; 17 | 18 | template 19 | struct GetTypeKind{ 20 | static const TypeKind Value = TypeKind::Class; 21 | }; 22 | 23 | template<> 24 | struct GetTypeKind{ 25 | static const TypeKind Value = TypeKind::AnyPointer; 26 | }; 27 | 28 | template 29 | struct GetTypeKind{ 30 | static const TypeKind Value = TypeKind::Enum; 31 | }; 32 | 33 | template 34 | struct GetTypeKind{ 35 | static const TypeKind Value = TypeKind::Reference; 36 | }; 37 | 38 | template 39 | struct GetTypeKind{ 40 | static const TypeKind Value = TypeKind::Pointer; 41 | }; 42 | 43 | template 44 | struct GetTypeKind{ 45 | static const TypeKind Value = TypeKind::RightValueReference; 46 | }; 47 | 48 | #define GET_TYPE_KIND(T) \ 49 | template<> \ 50 | struct GetTypeKind{ \ 51 | static const TypeKind Value = TypeKind::Fundamental; \ 52 | }; 53 | 54 | GET_TYPE_KIND(int8_t); 55 | GET_TYPE_KIND(int16_t); 56 | GET_TYPE_KIND(int32_t); 57 | GET_TYPE_KIND(int64_t); 58 | GET_TYPE_KIND(uint8_t); 59 | GET_TYPE_KIND(uint16_t); 60 | GET_TYPE_KIND(uint32_t); 61 | GET_TYPE_KIND(uint64_t); 62 | GET_TYPE_KIND(bool); 63 | GET_TYPE_KIND(float); 64 | GET_TYPE_KIND(double); 65 | GET_TYPE_KIND(signed long); 66 | GET_TYPE_KIND(unsigned long); 67 | GET_TYPE_KIND(wchar_t); 68 | 69 | #undef GET_TYPE_KIND 70 | 71 | #define kindof(T) GetTypeKind::type, std::is_enum::value>::Value 72 | 73 | class Value{ 74 | protected: 75 | QualifiedType type; 76 | public: 77 | virtual ~Value(){} 78 | virtual Value* Clone() const = 0; 79 | virtual Value* operator*() const{ 80 | THROW_EXCEPTION(InvalidOperation, "can not use * operator on a non-pointer object '" + type.ToString() + "'"); 81 | } 82 | virtual void* AddressOf() const{ 83 | THROW_EXCEPTION(InvalidOperation, "umimplemented addressof operation on class '" + type.ToString() + "'"); 84 | } 85 | const QualifiedType& GetType() const{ 86 | return type; 87 | } 88 | }; 89 | 90 | template 91 | class Holder : public Value{ 92 | private: 93 | friend class Any; 94 | T data; 95 | 96 | public: 97 | Holder(const T& data) : data(data) { type = qualified_typeof(T); } 98 | 99 | virtual Value* Clone() const override{ 100 | return new Holder(data); 101 | } 102 | 103 | virtual void* AddressOf() const override{ 104 | return (void*)&data;//new _Holder((T*)&data); 105 | } 106 | }; 107 | 108 | template 109 | using _Holder = Holder < T, kindof(T) > ; 110 | 111 | template<> 112 | class Holder : public Value{ 113 | private: 114 | friend class Any; 115 | void* data; 116 | 117 | public: 118 | Holder(void* data) : data(data) { type = qualified_typeof(void*); } 119 | 120 | virtual Value* Clone() const override{ 121 | return new Holder(data); 122 | } 123 | 124 | virtual Value* operator*() const override{ 125 | THROW_EXCEPTION(InvalidOperation, "can not use * operator on 'void*'"); 126 | } 127 | 128 | /*virtual Value* AddressOf() const override{ 129 | return new _Holder((void*)&data); 130 | }*/ 131 | }; 132 | 133 | template 134 | class Holder : public Value{ 135 | private: 136 | friend class Any; 137 | T* data; 138 | 139 | public: 140 | Holder(T* data) : data(data) { type = qualified_typeof(T*); } 141 | 142 | virtual Value* Clone() const override{ 143 | return new Holder(data); 144 | } 145 | 146 | virtual Value* operator*() const override{ 147 | return new Holder(*data); 148 | } 149 | 150 | /*virtual Value* AddressOf() const override{ 151 | return new _Holder((T*)&data); 152 | }*/ 153 | }; 154 | 155 | template 156 | class Holder : public Value{ 157 | private: 158 | friend class Any; 159 | T*& data; 160 | 161 | public: 162 | Holder(const T*& data) : data(data) { type = qualified_typeof(T*&); } 163 | 164 | virtual Value* Clone() const override{ 165 | return new Holder((T*&)data); 166 | } 167 | 168 | virtual Value* operator*() const override{ 169 | return new Holder((T&)*data); 170 | } 171 | 172 | /*virtual Value* AddressOf() const override{ 173 | return new _Holder((T*&)&data); 174 | }*/ 175 | }; 176 | 177 | //template 178 | //class Holder : Value{ 179 | //private: 180 | // friend class Any; 181 | // int64_t data; 182 | //public: 183 | // Holder(const T& data) : data((int64_t)data) { type = qualified_typeof(T); } 184 | 185 | // virtual Value* Clone() const override{ 186 | // return new Holder((T)data); 187 | // } 188 | 189 | // /*virtual Value* AddressOf() const override{ 190 | // return new _Holder(&data); 191 | // }*/ 192 | //}; 193 | 194 | class Any{ 195 | private: 196 | Value* value = nullptr; 197 | 198 | Any(Value* value) : value(value){ } 199 | 200 | public: 201 | /*Any(const Any& any) : value(any.value ? any.value->Clone() : nullptr){ 202 | 203 | }*/ 204 | 205 | /*Any(Any&& any){ 206 | std::swap(value, any.value); 207 | }*/ 208 | 209 | Any(const Any& any) : value(any.value ? any.value->Clone() : nullptr){ 210 | 211 | } 212 | 213 | Any(Any& any) : value(any.value ? any.value->Clone() : nullptr){ 214 | 215 | } 216 | 217 | //template 218 | //struct UseRef{ 219 | // static const bool Value = !std::is_fundamental::type>::value && !std::is_pointer::type>::value; 220 | //}; 221 | 222 | template 223 | Any(T* value){ 224 | this->value = new _Holder::type>(value); 225 | } 226 | 227 | /*template 228 | Any(std::shared_ptr value){ 229 | this->value = new _Holder::type>(value.get()); 230 | }*/ 231 | 232 | template::value>::type> 233 | Any(const T& value){ 234 | this->value = new _Holder::type>(value); 235 | } 236 | 237 | template 238 | Any(T& value){ 239 | //this->value = new _Holder::value || std::is_enum::value || std::is_pointer::type>::value, typename std::decay::type, typename std::decay::type&>::type>(value); 240 | this->value = new _Holder::type&>(value); 241 | } 242 | 243 | ~Any(){ 244 | delete value; 245 | value = nullptr; 246 | } 247 | 248 | bool IsEmpty() const{ 249 | return !value; 250 | } 251 | 252 | bool IsNull() const{ 253 | return GetType().IsPointer() && static_cast<_Holder*>(value)->data == nullptr; 254 | } 255 | 256 | const QualifiedType& GetType() const{ 257 | return value->GetType(); 258 | } 259 | 260 | Any& Swap(Any& any){ 261 | std::swap(value, any.value); 262 | return *this; 263 | } 264 | 265 | template 266 | Any& operator = (const T& value){ 267 | Any any(value); 268 | return Swap(any); 269 | } 270 | 271 | Any& operator = (Any any){ 272 | return Swap(any); 273 | } 274 | 275 | Any operator*() const{ 276 | return Any(**value); 277 | } 278 | 279 | /*Any& operator = (Any&& any){ 280 | return Swap(any); 281 | }*/ 282 | 283 | void* Cast() const{ 284 | if (IsEmpty()) 285 | THROW_EXCEPTION(InvalidCast, "invalid cast from an empty object to 'void*'"); 286 | 287 | if (!GetType().IsPointer()) 288 | return value->AddressOf(); 289 | //THROW_EXCEPTION(InvalidCast, "invalid cast from '" + GetType().ToString() + "' to 'void*'"); 290 | 291 | return static_cast<_Holder*>(value)->data; 292 | } 293 | 294 | template 295 | T Cast() const{ 296 | if (IsEmpty()) 297 | THROW_EXCEPTION(InvalidCast, "invalid cast from an empty object to '" + qualified_typeof(T).ToString() + "'"); 298 | 299 | auto type = GetType(); 300 | 301 | if (std::is_pointer::value && type == qualified_typeof(void*)) return (T) static_cast<_Holder*>(value)->data; 302 | if (std::is_pointer::value && type == qualified_typeof(void*&)) return (T) static_cast<_Holder*>(value)->data; 303 | 304 | QualifiedType t = qualified_typeof(T); 305 | if (t == GetType()) return (T) static_cast<_Holder*>(value)->data; 306 | 307 | if (std::is_enum::value && type == typeof(int64_t)) 308 | { 309 | if (t.IsReference()) 310 | return (T) static_cast<_Holder::value, int64_t, T>::type&>*>(value)->data; 311 | else 312 | return (T) static_cast<_Holder::value, int64_t, T>::type>*>(value)->data; 313 | } 314 | 315 | if (t.GetType() == type.GetType()){ 316 | switch (t.PointerCount()) 317 | { 318 | case 0: 319 | switch (type.PointerCount()) 320 | { 321 | case 1: 322 | return *static_cast<_Holder::type*>*>(value)->data; 323 | } 324 | //case 1: 325 | // switch (GetType().PointerCount()) 326 | // { 327 | // case 0: 328 | // return &static_cast::type>*>(value)->data; 329 | // } 330 | } 331 | } 332 | 333 | /*if (t.IsPointer() && type.GetType()->IsTemplate()){ 334 | TemplatedType* tt = (TemplatedType*)type.GetType(); 335 | if (tt->GetTemplateType() == template_typeof(std::shared_ptr)){ 336 | if (tt->MatchTemplates({ t.RemovePointer().GetType() })){ 337 | return static_cast<_Holder::type>>*>(value)->data.get(); 338 | } 339 | } 340 | }*/ 341 | 342 | // T& -> T ok 343 | // const T& -> T ok 344 | // const T -> T ok 345 | // T -> const T& ok 346 | // T -> const T ok 347 | // T -> T& error 348 | if (t.GetType() == type.GetType() && t.PointerCount() == type.PointerCount()){ 349 | if (type.IsLValueReference()) 350 | return (T)static_cast<_Holder::type&>*>(value)->data; 351 | else if (!std::is_reference::value || std::is_const::value) 352 | return (T)static_cast<_Holder::type>*>(value)->data; 353 | } 354 | 355 | THROW_EXCEPTION(InvalidCast, "invalid cast from '" + type.ToString() + "' to '" + qualified_typeof(T).ToString() + "'"); 356 | } 357 | 358 | operator void*() const{ 359 | return Cast(); 360 | } 361 | 362 | template 363 | operator T() const{ 364 | return Cast(); 365 | } 366 | 367 | std::string ToString(); 368 | }; 369 | 370 | #define CAST_(from, to) if (t == typeof(from)) return GetType().IsReference() ? (to)static_cast<_Holder*>(value)->data : (to)static_cast<_Holder*>(value)->data; 371 | #define CAST_ENUM(from, to) if (t->GetUnderlyingType() == typeof(from)) return GetType().IsReference() ? (to)static_cast<_Holder*>(value)->data : (to)static_cast<_Holder*>(value)->data; 372 | #define DEF_CAST(to) \ 373 | template<> \ 374 | inline to Any::Cast() const{ \ 375 | if(IsEmpty()) \ 376 | THROW_EXCEPTION(InvalidCast, "invalid cast from an empty object to '" + qualified_typeof(to).ToString() + "'"); \ 377 | if (!GetType().IsPointer()){ \ 378 | auto t = GetType().GetType(); \ 379 | CAST_(int8_t, to); \ 380 | CAST_(int16_t, to); \ 381 | CAST_(int32_t, to); \ 382 | CAST_(int64_t, to); \ 383 | CAST_(uint8_t, to); \ 384 | CAST_(uint16_t, to); \ 385 | CAST_(uint32_t, to); \ 386 | CAST_(uint64_t, to); \ 387 | CAST_(float, to); \ 388 | CAST_(double, to); \ 389 | \ 390 | if (t->IsEnum()){ \ 391 | CAST_ENUM(int8_t, to); \ 392 | CAST_ENUM(int16_t, to); \ 393 | CAST_ENUM(int32_t, to); \ 394 | CAST_ENUM(int64_t, to); \ 395 | CAST_ENUM(uint8_t, to); \ 396 | CAST_ENUM(uint16_t, to); \ 397 | CAST_ENUM(uint32_t, to); \ 398 | CAST_ENUM(uint64_t, to); \ 399 | } \ 400 | } \ 401 | THROW_EXCEPTION(InvalidCast, "invalid cast from '" + GetType().ToString() + "' to '" + qualified_typeof(to).ToString() + "'"); \ 402 | } 403 | 404 | /*template<> 405 | int64_t Cast() const{ 406 | if (IsEmpty()) 407 | THROW_EXCEPTION(InvalidCast, "invalid cast from an empty object to '" + qualified_typeof(int64_t).ToString() + "'"); 408 | if (!GetType().IsPointer()){ 409 | 410 | auto t = GetType().GetType(); 411 | CAST_(int8_t, int64_t); 412 | CAST_(int16_t, int64_t); 413 | CAST_(int32_t, int64_t); 414 | CAST_(int64_t, int64_t); 415 | CAST_(uint8_t, int64_t); 416 | CAST_(uint16_t, int64_t); 417 | CAST_(uint32_t, int64_t); 418 | CAST_(uint64_t, int64_t); 419 | CAST_(float, int64_t); 420 | CAST_(double, int64_t); 421 | 422 | if (GetType().IsEnum()) 423 | return GetType().IsReference() ? (int64_t) static_cast<_Holder*>(value)->data : (int64_t) static_cast<_Holder*>(value)->data; 424 | 425 | } 426 | THROW_EXCEPTION(InvalidCast, "invalid cast from '" + GetType().ToString() + "' to '" + qualified_typeof(int64_t).ToString() + "'"); 427 | }*/ 428 | 429 | DEF_CAST(int8_t); 430 | DEF_CAST(int16_t); 431 | DEF_CAST(int32_t); 432 | DEF_CAST(int64_t); 433 | DEF_CAST(uint8_t); 434 | DEF_CAST(uint16_t); 435 | DEF_CAST(uint32_t); 436 | DEF_CAST(uint64_t); 437 | DEF_CAST(float); 438 | DEF_CAST(double); 439 | #undef CAST_ 440 | #undef DEF_CAST 441 | -------------------------------------------------------------------------------- /src/qualified_type.cpp: -------------------------------------------------------------------------------- 1 | #include "qualified_type.h" 2 | #include "type.h" 3 | 4 | std::string QualifiedType::ToString() const{ 5 | if (!type) return "(null)"; 6 | 7 | std::stringstream ss; 8 | if (isConst) ss << "const "; 9 | if (isVolatile) ss << "volatile "; 10 | ss << type->GetName(); 11 | ss << std::string(pointerCount, '*'); 12 | if (referType == ReferType::Refer) ss << "&"; 13 | else if (referType == ReferType::RightRefer) ss << "&&"; 14 | return ss.str(); 15 | } 16 | 17 | bool QualifiedType::CanCast(const QualifiedType& t) const{ 18 | if (t.type->IsEnum()){ // const char* -> const string& 19 | if (t.type == type) 20 | return true; 21 | if (type == typeof(int64_t)) 22 | return true; 23 | } 24 | if (type->Is(t.type)){ 25 | if (pointerCount == 0 && t.pointerCount == 0 && !t.IsReference()) 26 | return true; 27 | if (pointerCount == t.pointerCount && (!isConst || t.isConst) && (!isVolatile || t.isVolatile) && (referType == ReferType::None || (referType == ReferType::Refer && t.referType != ReferType::None) || t.referType == ReferType::RightRefer)) 28 | return true; 29 | } 30 | return false;//t.type->GetConstructor({ *this }) != nullptr; 31 | } 32 | 33 | bool QualifiedType::IsNumber() const{ 34 | return type == int8Type || type == int16Type || type == int32Type || type == int64Type 35 | || type == uint8Type || type == uint16Type || type == uint32Type || type == uint64Type 36 | || type == floatType || type == doubleType; 37 | } 38 | 39 | bool QualifiedType::IsFloatingNumber() const{ 40 | return type == floatType || type == doubleType; 41 | } 42 | 43 | bool QualifiedType::IsIntegerNumber() const{ 44 | return type == int8Type || type == int16Type || type == int32Type || type == int64Type 45 | || type == uint8Type || type == uint16Type || type == uint32Type || type == uint64Type; 46 | } 47 | 48 | bool QualifiedType::IsBool() const{ 49 | return type == boolType; 50 | } 51 | 52 | bool QualifiedType::IsString() const{ 53 | return type == stringType || (type == charType && pointerCount == 1); 54 | } 55 | 56 | bool QualifiedType::IsEnum() const{ 57 | return type->IsEnum(); 58 | } 59 | -------------------------------------------------------------------------------- /src/qualified_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils.h" 4 | 5 | class Type; 6 | 7 | enum class ReferType{ None, Refer, RightRefer }; 8 | 9 | class QualifiedType{ 10 | protected: 11 | const Type* type = nullptr; 12 | bool isConst = false; 13 | bool isVolatile = false; 14 | int pointerCount = 0; 15 | ReferType referType = ReferType::None; 16 | 17 | public: 18 | 19 | QualifiedType(){ 20 | 21 | } 22 | 23 | QualifiedType(const Type* type){ 24 | this->type = type; 25 | } 26 | 27 | QualifiedType(QualifiedType type, bool isPointer, bool isConst, bool isVolatile, ReferType referType){ 28 | this->type = type.type; 29 | this->isConst = type.isConst; 30 | this->isVolatile = type.isVolatile; 31 | this->referType = type.referType; 32 | this->pointerCount = type.pointerCount; 33 | 34 | if (isPointer) pointerCount++; 35 | if (isConst) this->isConst = true; 36 | if (isVolatile) this->isVolatile = true; 37 | if (referType != ReferType::None) this->referType = referType; 38 | } 39 | 40 | const Type* GetType() const{ 41 | return type; 42 | } 43 | 44 | bool IsNumber() const; 45 | 46 | bool IsFloatingNumber() const; 47 | 48 | bool IsIntegerNumber() const; 49 | 50 | bool IsBool() const; 51 | 52 | bool IsString() const; 53 | 54 | bool IsEnum() const; 55 | 56 | QualifiedType RemoveCV() const{ 57 | QualifiedType t = *this; 58 | t.isConst = false; 59 | t.isVolatile = false; 60 | return t; 61 | } 62 | 63 | QualifiedType RemoveReference() const{ 64 | QualifiedType t = *this; 65 | t.referType = ReferType::None; 66 | return t; 67 | } 68 | 69 | QualifiedType RemovePointer() const{ 70 | if (!IsPointer()) 71 | return *this; 72 | QualifiedType t = *this; 73 | t.pointerCount--; 74 | return t; 75 | } 76 | 77 | bool CanCast(const QualifiedType& t) const; 78 | 79 | bool IsConst() const{ 80 | return isConst; 81 | } 82 | 83 | bool IsVolatile() const{ 84 | return isVolatile; 85 | } 86 | 87 | bool IsPointer() const{ 88 | return pointerCount > 0; 89 | } 90 | 91 | int PointerCount() const{ 92 | return pointerCount; 93 | } 94 | 95 | ReferType ReferType() const{ 96 | return referType; 97 | } 98 | 99 | bool IsReference() const{ 100 | return referType != ReferType::None; 101 | } 102 | 103 | bool IsLValueReference() const{ 104 | return referType == ReferType::Refer; 105 | } 106 | 107 | bool IsRValueReference() const{ 108 | return referType == ReferType::RightRefer; 109 | } 110 | 111 | std::string ToString() const; 112 | 113 | /*operator const Type*() const{ 114 | return type; 115 | }*/ 116 | 117 | bool operator==(const QualifiedType& t) const{ 118 | return type == t.type && isConst == t.isConst && isVolatile == t.isVolatile && pointerCount == t.pointerCount && referType == t.referType; 119 | } 120 | 121 | bool operator!=(const QualifiedType& t) const{ 122 | return !operator==(t); 123 | } 124 | }; 125 | 126 | template 127 | struct GetQualifiedType{ 128 | static const QualifiedType Value(){ 129 | return typeof(T); 130 | } 131 | }; 132 | 133 | #define qualified_typeof(type) GetQualifiedType::Value() 134 | 135 | #define GET_QUALIFIED_TYPE(TYPE, ...) \ 136 | template \ 137 | struct GetQualifiedType{ \ 138 | static const QualifiedType Value(){ \ 139 | return QualifiedType(GetQualifiedType::Value(), __VA_ARGS__); \ 140 | } \ 141 | }; 142 | 143 | GET_QUALIFIED_TYPE(T&, false, false, false, ReferType::Refer); 144 | GET_QUALIFIED_TYPE(T&&, false, false, false, ReferType::RightRefer); 145 | GET_QUALIFIED_TYPE(T*, true, false, false, ReferType::None); 146 | GET_QUALIFIED_TYPE(const T, false, true, false, ReferType::None); 147 | GET_QUALIFIED_TYPE(const T&, false, true, false, ReferType::Refer); 148 | GET_QUALIFIED_TYPE(const T&&, false, true, false, ReferType::RightRefer); 149 | GET_QUALIFIED_TYPE(const T*, true, true, false, ReferType::None); 150 | GET_QUALIFIED_TYPE(volatile T, false, false, true, ReferType::None); 151 | GET_QUALIFIED_TYPE(volatile T&, false, false, true, ReferType::Refer); 152 | GET_QUALIFIED_TYPE(volatile T&&, false, false, true, ReferType::RightRefer); 153 | GET_QUALIFIED_TYPE(volatile T*, true, false, true, ReferType::None); 154 | GET_QUALIFIED_TYPE(const volatile T, false, true, true, ReferType::None); 155 | GET_QUALIFIED_TYPE(const volatile T&, false, true, true, ReferType::Refer); 156 | GET_QUALIFIED_TYPE(const volatile T&&, false, true, true, ReferType::RightRefer); 157 | GET_QUALIFIED_TYPE(const volatile T*, true, true, true, ReferType::None); 158 | 159 | #undef GET_QUALIFIED_TYPE 160 | -------------------------------------------------------------------------------- /src/reflection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "exception.h" 4 | #include "type.h" 5 | #include "enum.h" 6 | #include "constructor.h" 7 | #include "field.h" 8 | #include "method.h" 9 | 10 | 11 | template 12 | const Field* make_field(const std::string& name, FieldType OwnerType::* field){ 13 | return new MemberField(name.substr(name.find_last_of(':') + 1), field); 14 | } 15 | 16 | template 17 | const Field* make_field(const std::string& name, FieldType* field){ 18 | return new StaticField(name.substr(name.find_last_of(':') + 1), field); 19 | } 20 | 21 | template 22 | const Field* make_field(const std::string& name, const FieldType OwnerType::* field){ 23 | return new ReadonlyField(name.substr(name.find_last_of(':') + 1), field); 24 | } 25 | 26 | template 27 | const Field* make_field(const std::string& name, const FieldType* field){ 28 | return new ConstField(name.substr(name.find_last_of(':') + 1), field); 29 | } 30 | 31 | template 32 | const Method* make_method(const std::string& name, ReturnType(OwnerType::*fun)(Args...)){ 33 | return new MemberMethod(name.substr(name.find_last_of(':') + 1), fun); 34 | } 35 | 36 | template 37 | const Method* make_method(const std::string& name, ReturnType(OwnerType::*fun)(Args...) const){ 38 | return new MemberMethod(name.substr(name.find_last_of(':') + 1), (ReturnType(OwnerType::*)(Args...))fun); 39 | } 40 | 41 | template 42 | const Method* make_method(const std::string& name, ReturnType(*fun)(Args...)){ 43 | return new StaticMethod(name.substr(name.find_last_of(':') + 1), fun); 44 | } 45 | 46 | #define BEGIN_DERIVED_TYPE(TYPE, BASE) \ 47 | public: \ 48 | static const Type* StaticType(){ \ 49 | static const Type* type = nullptr; \ 50 | if (type == nullptr){ \ 51 | type = new Type(); \ 52 | type = Type::RegisterType(const_cast(typeof(TYPE)), #TYPE, typeof(BASE)) 53 | #define END_TYPE ; \ 54 | } \ 55 | return type; \ 56 | } \ 57 | virtual const Type* GetType() const{ \ 58 | return StaticType(); \ 59 | } \ 60 | private: 61 | #define BEGIN_TYPE(TYPE) BEGIN_DERIVED_TYPE(TYPE, std::nullptr_t) 62 | 63 | #define CTORS(...) ->AddConstructors(std::vector{__VA_ARGS__}) 64 | #define FIELDS(...) ->AddFields(std::vector{__VA_ARGS__}) 65 | #define METHODS(...) ->AddMethods(std::vector{__VA_ARGS__}) 66 | #define CTOR(TYPE, ...) new ConstructorImpl() 67 | #define EMPTY_CTOR(TYPE) new ConstructorImpl() 68 | #define COPY_CTOR(TYPE) new ConstructorImpl() 69 | #define DEFAULT_CTOR(TYPE) EMPTY_CTOR(TYPE), COPY_CTOR(TYPE) 70 | #define FIELD(field) make_field(#field, field) 71 | #define METHOD(fun) make_method(#fun, fun) 72 | 73 | #undef THROW_EXCEPTION 74 | -------------------------------------------------------------------------------- /src/string_helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils.h" 4 | 5 | class StringHelper{ 6 | public: 7 | 8 | static std::vector Split(const std::string& str, char splitChar){ 9 | std::vector ret; 10 | int start = 0; 11 | for (int i = 0, len = str.length(); i < len; i++){ 12 | if (str[i] == splitChar){ 13 | ret.push_back(str.substr(start, i - start)); 14 | start = i + 1; 15 | } 16 | } 17 | ret.push_back(str.substr(start)); 18 | return ret; 19 | } 20 | 21 | static std::string RemoveSpaces(const std::string& str){ 22 | std::vector ret; 23 | for (int i = 0, len = str.length(); i < len; i++){ 24 | char c = str[i]; 25 | if (c != ' ' && c != '\t' && c != '\n'&& c != '\r') 26 | ret.push_back(c); 27 | } 28 | return std::string(ret.begin(), ret.end()); 29 | } 30 | 31 | }; 32 | -------------------------------------------------------------------------------- /src/type.cpp: -------------------------------------------------------------------------------- 1 | #include "type.h" 2 | #include "constructor.h" 3 | #include "field.h" 4 | #include "method.h" 5 | 6 | std::string Type::GetDescription() const{ 7 | std::stringstream ss; 8 | ss << "class " << name; 9 | if (baseType) ss << " : " << baseType->GetName(); 10 | ss << " {" << std::endl; 11 | for (auto f : GetFields()){ 12 | ss << " " << f->GetDescription(f->GetOwnerType() != this) << ";" << std::endl; 13 | } 14 | ss << std::endl; 15 | for (auto c : GetConstructors()){ 16 | ss << " " << c->GetDescription() << ";" << std::endl; 17 | } 18 | ss << std::endl; 19 | for (auto m : GetMethods()){ 20 | ss << " " << m->GetDescription(m->GetOwnerType() != this) << ";" << std::endl; 21 | } 22 | ss << "};" << std::endl; 23 | return ss.str(); 24 | } 25 | 26 | Type* Type::AddFields(const std::vector& fields){ 27 | for (auto f : fields){ 28 | if (f->GetOwnerType() == nullptr) 29 | const_cast(f)->ownerType = this; 30 | (f->IsStatic() ? this->static_fields : this->fields).push_back(f); 31 | fieldsMap.insert(std::make_pair(f->GetName(), f)); 32 | } 33 | return this; 34 | } 35 | 36 | Type* Type::AddMethods(const std::vector& methods){ 37 | for (auto m : methods){ 38 | if (m->GetOwnerType() == nullptr) 39 | const_cast(m)->ownerType = this; 40 | (m->IsStatic() ? this->static_methods : this->methods).push_back(m); 41 | methodsMap[m->GetName()].push_back(m); 42 | } 43 | return this; 44 | } 45 | 46 | Type* Type::AddConstructors(const std::vector& constructors){ 47 | for (auto c : constructors){ 48 | this->constructors.push_back(c); 49 | } 50 | return this; 51 | } 52 | 53 | const Constructor* Type::GetConstructor(const std::vector& paramTypes) const{ 54 | std::vector matches; 55 | 56 | for (auto c : constructors){ 57 | if (MatchParams(c->GetParamTypes(), paramTypes))//c->GetParamTypes() == paramTypes) 58 | return c;//matches.push_back(c); 59 | } 60 | 61 | if (matches.empty()){ 62 | return nullptr; 63 | } 64 | if (matches.size() > 1){ 65 | std::stringstream err; 66 | err << "constructor '" << name << "' ambiguous matched between: " << std::endl; 67 | for (auto m : matches){ 68 | err << "\t" << m->GetDescription() << std::endl; 69 | } 70 | THROW_EXCEPTION(AmbiguousMatched, err.str()); 71 | } 72 | else{ 73 | return matches[0]; 74 | } 75 | } 76 | 77 | const Field* Type::GetField(const std::string& fieldName) const{ 78 | auto f = fieldsMap[fieldName]; 79 | 80 | if (f == nullptr && baseType != nullptr){ 81 | return baseType->GetField(fieldName); 82 | } 83 | 84 | return f; 85 | } 86 | 87 | const Method* Type::GetMethod(const std::string& methodName) const{ 88 | auto ms = GetMethods(); 89 | std::vector matches; 90 | 91 | for (auto m : ms){ 92 | if (m->GetName() == methodName) 93 | matches.push_back(m); 94 | } 95 | 96 | if (matches.empty()) { 97 | return nullptr; 98 | } 99 | else if (matches.size() > 1) { 100 | std::stringstream err; 101 | err << "method '" << methodName << "' ambiguous matched between: " << std::endl; 102 | for (auto m : matches){ 103 | err << "\t" << m->GetDescription() << std::endl; 104 | } 105 | THROW_EXCEPTION(AmbiguousMatched, err.str()); 106 | } 107 | else { 108 | return matches[0]; 109 | } 110 | /*auto ms = methodsMap[methodName]; 111 | 112 | if (ms.size()>1) { 113 | std::stringstream err; 114 | err << "method '" << methodName << "' ambiguous matched between: " << std::endl; 115 | for(auto m : ms){ 116 | err << "\t" << m->GetDescription() << endl; 117 | } 118 | throw err.str(); 119 | } 120 | 121 | if (ms.empty()) { 122 | if(baseType == nullptr) 123 | return nullptr; 124 | else 125 | return baseType->GetMethod(methodName); 126 | } else { 127 | if(baseType != nullptr && baseType->GetMethod(methodName) != nullptr){ 128 | std::stringstream err; 129 | err << "method '" << methodName << "' ambiguous matched between: " << std::endl; 130 | err << "\t" << ms[0]->GetDescription() << endl; 131 | err << "\t" << baseType->GetMethod(methodName)->GetDescription() << endl; 132 | throw err.str(); 133 | }else{ 134 | return ms[0]; 135 | } 136 | }*/ 137 | } 138 | 139 | const Method* Type::GetMethod(const std::string& methodName, const std::vector& paramTypes) const{ 140 | auto ms = methodsMap[methodName]; 141 | std::vector matches; 142 | 143 | if (!ms.empty()) { 144 | for (auto m : ms) { 145 | if (MatchParams(m->GetParamTypes(), paramTypes)){//paramTypes == m->GetParamTypes()){ 146 | matches.push_back(m); 147 | } 148 | } 149 | } 150 | 151 | if (baseType != nullptr){ 152 | //return baseType->GetMethod(methodName, paramTypes); 153 | auto r = baseType->GetMethod(methodName, paramTypes); 154 | if (r) matches.push_back(r); 155 | } 156 | 157 | if (matches.empty()){ 158 | return nullptr; 159 | } 160 | else if (matches.size() > 1){ 161 | std::stringstream err; 162 | err << "method '" << name << "("; 163 | for (int i = 0, n = paramTypes.size(); i < n; i++){ 164 | if (i != 0) err << ", "; 165 | err << paramTypes[i].ToString(); 166 | } 167 | err << ")' ambiguous matched between: " << std::endl; 168 | for (auto m : matches){ 169 | err << "\t" << m->GetDescription() << std::endl; 170 | } 171 | THROW_EXCEPTION(AmbiguousMatched, err.str()); 172 | } 173 | else{ 174 | return matches[0]; 175 | } 176 | } 177 | 178 | bool TemplatedType::Is(const Type* type) const{ 179 | if (templateType == template_typeof(std::shared_ptr) && type->IsTemplate() && type->IsComplete() && ((TemplatedType*)type)->templateType == template_typeof(std::shared_ptr)){ 180 | auto t1 = templates[0]; 181 | auto t2 = ((TemplatedType*)type)->templates[0]; 182 | return t1.ReferType() == t2.ReferType() && !t1.IsPointer() && !t2.IsPointer() && (!t1.IsConst() || t2.IsConst()) && (!t1.IsVolatile() || t2.IsVolatile()) && t1.GetType()->Is(t2.GetType()); 183 | } 184 | return Type::Is(type); 185 | } 186 | 187 | const Type* Null::GetType(){ 188 | static const Type type; 189 | return &type; 190 | } 191 | 192 | #define IMPL_REFLECT_PRIMITIVE_TYPE(typeName) \ 193 | const Type* ReflectType::type = typeof(typeName); 194 | #define IMPL_REFLECT_ALIASED_PRIMITIVE_TYPE(TYPE, REAL_TYPE) \ 195 | const Type* ReflectType::type = typeof(TYPE); 196 | 197 | IMPL_REFLECT_PRIMITIVE_TYPE(void) 198 | IMPL_REFLECT_PRIMITIVE_TYPE(int8_t) 199 | IMPL_REFLECT_PRIMITIVE_TYPE(int16_t) 200 | IMPL_REFLECT_PRIMITIVE_TYPE(int32_t) 201 | IMPL_REFLECT_PRIMITIVE_TYPE(int64_t) 202 | IMPL_REFLECT_PRIMITIVE_TYPE(uint8_t) 203 | IMPL_REFLECT_PRIMITIVE_TYPE(uint16_t) 204 | IMPL_REFLECT_PRIMITIVE_TYPE(uint32_t) 205 | IMPL_REFLECT_PRIMITIVE_TYPE(uint64_t) 206 | IMPL_REFLECT_PRIMITIVE_TYPE(float) 207 | IMPL_REFLECT_PRIMITIVE_TYPE(double) 208 | IMPL_REFLECT_PRIMITIVE_TYPE(bool) 209 | IMPL_REFLECT_PRIMITIVE_TYPE(std::string) 210 | IMPL_REFLECT_PRIMITIVE_TYPE(std::wstring) 211 | 212 | #if defined(CHAR_MIN) && (CHAR_MIN == 0) 213 | IMPL_REFLECT_ALIASED_PRIMITIVE_TYPE(char, uint8_t) 214 | #else 215 | IMPL_REFLECT_ALIASED_PRIMITIVE_TYPE(char, int8_t) 216 | #endif 217 | 218 | #if defined(WCHAR_MAX) && (WCHAR_MAX == 0xffffffffL) 219 | IMPL_REFLECT_ALIASED_PRIMITIVE_TYPE(wchar_t, uint32_t) 220 | #else 221 | IMPL_REFLECT_ALIASED_PRIMITIVE_TYPE(wchar_t, uint16_t) 222 | #endif 223 | 224 | #if defined(LONG_MAX) && (LONG_MAX > 0xffffffffL) 225 | IMPL_REFLECT_ALIASED_PRIMITIVE_TYPE(signed long, int64_t) 226 | IMPL_REFLECT_ALIASED_PRIMITIVE_TYPE(unsigned long, uint64_t) 227 | #else 228 | IMPL_REFLECT_ALIASED_PRIMITIVE_TYPE(signed long, int32_t) 229 | IMPL_REFLECT_ALIASED_PRIMITIVE_TYPE(unsigned long, uint32_t) 230 | #endif 231 | 232 | #undef IMPL_REFLECT_PRIMITIVE_TYPE 233 | #undef IMPL_REFLECT_ALIASED_PRIMITIVE_TYPE 234 | 235 | ____DUMMY_ADD_ALIASED::____DUMMY_ADD_ALIASED(){ 236 | #define ADD_ALIAS(type) Type::AddAlias(#type, typeof(type)) 237 | 238 | ADD_ALIAS(int); 239 | ADD_ALIAS(signed int); 240 | ADD_ALIAS(unsigned int); 241 | ADD_ALIAS(short); 242 | ADD_ALIAS(signed short); 243 | ADD_ALIAS(unsigned short); 244 | ADD_ALIAS(long); 245 | ADD_ALIAS(long long); 246 | ADD_ALIAS(signed long long); 247 | ADD_ALIAS(unsigned long long); 248 | ADD_ALIAS(signed char); 249 | ADD_ALIAS(unsigned char); 250 | #undef ADD_ALIAS 251 | 252 | #define ADD_ALIAS2(type) Type::AddAlias(#type, typeof(type##_t)) 253 | ADD_ALIAS2(int8); 254 | ADD_ALIAS2(int16); 255 | ADD_ALIAS2(int32); 256 | ADD_ALIAS2(int64); 257 | ADD_ALIAS2(uint8); 258 | ADD_ALIAS2(uint16); 259 | ADD_ALIAS2(uint32); 260 | ADD_ALIAS2(uint64); 261 | #undef ADD_ALIAS2 262 | 263 | Type::AddAlias("Int8", typeof(int8_t)); 264 | Type::AddAlias("Int16", typeof(int16_t)); 265 | Type::AddAlias("Int32", typeof(int32_t)); 266 | Type::AddAlias("Int64", typeof(int64_t)); 267 | Type::AddAlias("UInt8", typeof(uint8_t)); 268 | Type::AddAlias("UInt16", typeof(uint16_t)); 269 | Type::AddAlias("UInt32", typeof(uint32_t)); 270 | Type::AddAlias("UInt64", typeof(uint64_t)); 271 | 272 | Type::AddAlias("Int", typeof(int)); 273 | Type::AddAlias("Integer", typeof(int)); 274 | Type::AddAlias("Float", typeof(float)); 275 | Type::AddAlias("Double", typeof(double)); 276 | Type::AddAlias("Long", typeof(long)); 277 | Type::AddAlias("Bool", typeof(bool)); 278 | Type::AddAlias("Boolean", typeof(bool)); 279 | Type::AddAlias("string", typeof(std::string)); 280 | Type::AddAlias("String", typeof(std::string)); 281 | Type::AddAlias("wstring", typeof(std::wstring)); 282 | Type::AddAlias("WString", typeof(std::wstring)); 283 | 284 | const_cast(typeof(std::string))->AddConstructors({ new ConstructorImpl(), new ConstructorImpl(), new ConstructorImpl() }); 285 | } 286 | 287 | const ____DUMMY_ADD_ALIASED instance; 288 | -------------------------------------------------------------------------------- /src/type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils.h" 4 | #include "exception.h" 5 | #include "qualified_type.h" 6 | 7 | class Field; 8 | class Method; 9 | class Constructor; 10 | 11 | class Type{ 12 | protected: 13 | friend class TemplatedType; 14 | 15 | std::string name; 16 | const Type* baseType; 17 | const Type* underlyingType = nullptr; 18 | 19 | std::vector constructors; 20 | std::vector fields; 21 | std::vector methods; 22 | 23 | std::vector static_fields; 24 | std::vector static_methods; 25 | 26 | mutable std::unordered_map fieldsMap; 27 | mutable std::unordered_map> methodsMap; 28 | 29 | bool isEnum = false; 30 | int templateCount; 31 | bool templated = false; 32 | 33 | static std::unordered_map& GetTypes(){ 34 | static std::unordered_map types; 35 | return types; 36 | } 37 | 38 | static bool MatchParams(const std::vector& src, const std::vector& match){ 39 | if (src.size() != match.size()) 40 | return false; 41 | 42 | for (int i = 0, n = src.size(); i < n; i++){ 43 | if (match[i] == src[i]); 44 | else if (match[i].CanCast(src[i])); 45 | else return false; 46 | } 47 | 48 | return true; 49 | } 50 | 51 | public: 52 | Type(int templateCount = 0){ 53 | this->name = "Unregistered_Type"; 54 | this->baseType = nullptr; 55 | } 56 | 57 | bool IsTemplate() const{ 58 | return templateCount != 0; 59 | } 60 | 61 | bool IsComplete() const{ 62 | return !IsTemplate() || templated; 63 | } 64 | 65 | std::string GetDescription() const; 66 | 67 | static Type* RegisterEnum(Type* type, const std::string& name, const Type* underlyingType){ 68 | if (GetTypes().find(name) != GetTypes().end()) 69 | THROW_EXCEPTION(TypeAlreadyExists, "there is already a type named '" + name + "'"); 70 | 71 | //std::cout << "register enum " << name << std::endl; 72 | 73 | const_cast(type)->name = name; 74 | const_cast(type)->isEnum = true; 75 | GetTypes().insert(std::make_pair(name, type)); 76 | type->underlyingType = underlyingType; 77 | 78 | return type; 79 | } 80 | 81 | static Type* RegisterType(Type* type, const std::string& name, const Type* baseType){ 82 | if (GetTypes().find(name) != GetTypes().end()) 83 | THROW_EXCEPTION(TypeAlreadyExists, "there is already a type named '" + name + "'"); 84 | 85 | //std::cout << "register class " << name << std::endl; 86 | 87 | const_cast(type)->name = name; 88 | const_cast(type)->baseType = baseType; 89 | GetTypes().insert(std::make_pair(name, type)); 90 | 91 | return type; 92 | } 93 | 94 | Type* AddConstructors(const std::vector& constructors); 95 | Type* AddFields(const std::vector& fields); 96 | Type* AddMethods(const std::vector& methods); 97 | 98 | virtual bool Is(const Type* type) const{ 99 | if (type == this) 100 | return true; 101 | 102 | if (baseType != nullptr) 103 | return baseType->Is(type); 104 | 105 | return false; 106 | } 107 | 108 | static const Type* AddAlias(const std::string& name, const Type* type){ 109 | if (GetTypes().find(name) != GetTypes().end()) 110 | THROW_EXCEPTION(TypeAlreadyExists, "there is already a type named '" + name + "'"); 111 | 112 | //std::cout << "add alias " << name << " -> " << type->GetName() << std::endl; 113 | 114 | GetTypes().insert(std::make_pair(name, type)); 115 | 116 | return type; 117 | } 118 | 119 | static const Type* GetType(const std::string& typeName, bool throwIfNotFound = false){ 120 | auto type = GetTypes()[typeName]; 121 | 122 | if (throwIfNotFound && type == nullptr){ 123 | THROW_EXCEPTION(TypeNotFound, "type '" + typeName + "' not found"); 124 | } 125 | 126 | return type; 127 | } 128 | 129 | bool IsEnum() const{ 130 | return isEnum; 131 | } 132 | 133 | virtual std::string GetName() const{ 134 | return name; 135 | } 136 | 137 | const Type* GetBaseType() const{ 138 | return baseType; 139 | } 140 | 141 | const Type* GetUnderlyingType() const{ 142 | return underlyingType; 143 | } 144 | 145 | const std::vector& GetConstructors() const{ 146 | return constructors; 147 | } 148 | 149 | const Constructor* GetConstructor() const{ 150 | auto ctr = GetConstructor({}); 151 | if (ctr == nullptr) 152 | THROW_EXCEPTION(NoDefualtConstructor, "class '" + name + "' has no default constructor"); 153 | return ctr; 154 | } 155 | 156 | const Constructor* GetConstructor(const std::vector& paramTypes) const; 157 | 158 | std::vector GetMemberFields() const{ 159 | auto fs = fields; 160 | 161 | if (baseType != nullptr){ 162 | auto baseFields = baseType->GetMemberFields(); 163 | fs.insert(fs.begin(), baseFields.begin(), baseFields.end()); 164 | } 165 | 166 | return fs; 167 | } 168 | 169 | std::vector GetStaticFields() const{ 170 | auto fs = static_fields; 171 | 172 | if (baseType != nullptr){ 173 | auto baseFields = baseType->GetStaticFields(); 174 | fs.insert(fs.begin(), baseFields.begin(), baseFields.end()); 175 | } 176 | 177 | return fs; 178 | } 179 | 180 | std::vector GetMemberMethods() const{ 181 | auto ms = methods; 182 | 183 | if (baseType != nullptr){ 184 | auto baseMethods = baseType->GetMemberMethods(); 185 | ms.insert(ms.begin(), baseMethods.begin(), baseMethods.end()); 186 | } 187 | 188 | return ms; 189 | } 190 | 191 | std::vector GetStaticMethods() const{ 192 | auto ms = static_methods; 193 | 194 | if (baseType != nullptr){ 195 | auto baseMethods = baseType->GetStaticMethods(); 196 | ms.insert(ms.begin(), baseMethods.begin(), baseMethods.end()); 197 | } 198 | 199 | return ms; 200 | } 201 | 202 | std::vector GetFields() const{ 203 | auto fs = GetMemberFields(); 204 | auto fs2 = GetStaticFields(); 205 | fs.insert(fs.end(), fs2.begin(), fs2.end()); 206 | return fs; 207 | } 208 | 209 | std::vector GetMethods() const{ 210 | auto ms = GetMemberMethods(); 211 | auto ms2 = GetStaticMethods(); 212 | ms.insert(ms.end(), ms2.begin(), ms2.end()); 213 | return ms; 214 | } 215 | 216 | // find a field by name 217 | const Field* GetField(const std::string& fieldName) const; 218 | 219 | // find a method by name, just uses while the method has no overloads 220 | const Method* GetMethod(const std::string& methodName) const; 221 | 222 | // find a method by its signature 223 | const Method* GetMethod(const std::string& methodName, const std::vector& paramTypes) const; 224 | 225 | }; 226 | 227 | class TemplatedType : public Type{ 228 | protected: 229 | std::vector templates; 230 | const Type* templateType; 231 | 232 | public: 233 | TemplatedType(const Type* type, const std::vector& templates){ 234 | templateType = type; 235 | if (templateCount == 0) 236 | THROW_EXCEPTION(InvalidArguments, "tried to register an non-template class as an templated type"); 237 | this->templates = templates; 238 | templated = true; 239 | } 240 | 241 | virtual std::string GetName() const override{ 242 | std::stringstream ss; 243 | ss << templateType->name << "<"; 244 | ss << templates[0].ToString(); 245 | for (int i = 1, n = templates.size(); i < n; i++){ 246 | ss << ", " << templates[i].ToString(); 247 | } 248 | ss << ">"; 249 | return ss.str(); 250 | } 251 | 252 | const std::vector& GetTemplates() const{ 253 | return templates; 254 | } 255 | 256 | const Type* GetTemplateType() const{ 257 | return templateType; 258 | } 259 | 260 | bool MatchTemplates(const std::vector& templates){ 261 | return templates == this->templates; 262 | } 263 | 264 | virtual bool Is(const Type* type) const; 265 | 266 | }; 267 | 268 | #define REFLECT_PRIMITIVE_TYPE(typeName) \ 269 | template<> \ 270 | struct ReflectType{ \ 271 | static const Type* type; \ 272 | static const Type* Value(){ \ 273 | static const Type* type = Type::RegisterType(new Type, #typeName, nullptr); \ 274 | return type; \ 275 | } \ 276 | }; 277 | 278 | #define REFLECT_ALIASED_PRIMITIVE_TYPE(TYPE, REAL_TYPE) \ 279 | template<> \ 280 | struct ReflectType{ \ 281 | static const Type* type; \ 282 | static const Type* Value(){ \ 283 | static const Type* type = Type::AddAlias(#TYPE, typeof(REAL_TYPE)); \ 284 | return type; \ 285 | } \ 286 | }; 287 | 288 | // make primitive types reflectable 289 | // doesn't consider long double, it's not recommanded to use 290 | 291 | REFLECT_PRIMITIVE_TYPE(void) 292 | REFLECT_PRIMITIVE_TYPE(int8_t) 293 | REFLECT_PRIMITIVE_TYPE(int16_t) 294 | REFLECT_PRIMITIVE_TYPE(int32_t) 295 | REFLECT_PRIMITIVE_TYPE(int64_t) 296 | REFLECT_PRIMITIVE_TYPE(uint8_t) 297 | REFLECT_PRIMITIVE_TYPE(uint16_t) 298 | REFLECT_PRIMITIVE_TYPE(uint32_t) 299 | REFLECT_PRIMITIVE_TYPE(uint64_t) 300 | REFLECT_PRIMITIVE_TYPE(float) 301 | REFLECT_PRIMITIVE_TYPE(double) 302 | REFLECT_PRIMITIVE_TYPE(bool) 303 | REFLECT_PRIMITIVE_TYPE(std::string) 304 | REFLECT_PRIMITIVE_TYPE(std::wstring) 305 | 306 | #undef REFLECT_PRIMITIVE_TYPE 307 | 308 | #if defined(CHAR_MIN) && (CHAR_MIN == 0) 309 | REFLECT_ALIASED_PRIMITIVE_TYPE(char, uint8_t) 310 | #else 311 | REFLECT_ALIASED_PRIMITIVE_TYPE(char, int8_t) 312 | #endif 313 | 314 | #if defined(WCHAR_MAX) && (WCHAR_MAX == 0xffffffffL) 315 | REFLECT_ALIASED_PRIMITIVE_TYPE(wchar_t, uint32_t) 316 | #else 317 | REFLECT_ALIASED_PRIMITIVE_TYPE(wchar_t, uint16_t) 318 | #endif 319 | 320 | #if defined(LONG_MAX) && (LONG_MAX > 0xffffffffL) 321 | REFLECT_ALIASED_PRIMITIVE_TYPE(signed long, int64_t) 322 | REFLECT_ALIASED_PRIMITIVE_TYPE(unsigned long, uint64_t) 323 | #else 324 | REFLECT_ALIASED_PRIMITIVE_TYPE(signed long, int32_t) 325 | REFLECT_ALIASED_PRIMITIVE_TYPE(unsigned long, uint32_t) 326 | #endif 327 | 328 | #undef REFLECT_ALIASED_PRIMITIVE_TYPE 329 | 330 | class ____DUMMY_ADD_ALIASED{ 331 | static const ____DUMMY_ADD_ALIASED instance; 332 | public: 333 | ____DUMMY_ADD_ALIASED(); 334 | }; 335 | 336 | #define DEF_TMPL(T, n) \ 337 | template<> \ 338 | struct TemplateType{ \ 339 | static const Type* type; \ 340 | static const Type* Value(){ \ 341 | static const Type* type = Type::RegisterType(new Type(n), #T, nullptr); \ 342 | return type; \ 343 | } \ 344 | }; 345 | 346 | DEF_TMPL(std::shared_ptr, 1) 347 | DEF_TMPL(std::vector, 2) 348 | 349 | #define DEF_CT1(C) \ 350 | template \ 351 | struct ReflectType>{ \ 352 | static const Type* type; \ 353 | static const Type* Value(){ \ 354 | static const Type* type = Type::RegisterType(new Type, #C "<" + qualified_typeof(T).ToString() + ">", nullptr); \ 355 | return type; \ 356 | } \ 357 | }; 358 | #undef DEF_CT1 359 | 360 | #define DEF_CT1(C) \ 361 | template \ 362 | struct ReflectType>{ \ 363 | static const Type* type; \ 364 | static const Type* Value(){ \ 365 | static const Type* type = new TemplatedType(TemplateType::Value(), {qualified_typeof(T)...}); \ 366 | return type; \ 367 | } \ 368 | }; 369 | 370 | DEF_CT1(std::shared_ptr); 371 | DEF_CT1(std::vector); 372 | 373 | //template 374 | //struct ReflectType>{ 375 | // static const Type* type; 376 | // static const Type* Value(){ 377 | // static const Type* type = Type::RegisterType(new Type, "std::vector<" + qualified_typeof(T).ToString() + ">", nullptr); 378 | // return type; 379 | // } 380 | //}; 381 | 382 | 383 | static const Type* int8Type = typeof(int8_t); 384 | static const Type* int16Type = typeof(int16_t); 385 | static const Type* int32Type = typeof(int32_t); 386 | static const Type* int64Type = typeof(int64_t); 387 | static const Type* uint8Type = typeof(uint8_t); 388 | static const Type* uint16Type = typeof(uint16_t); 389 | static const Type* uint32Type = typeof(uint32_t); 390 | static const Type* uint64Type = typeof(uint64_t); 391 | static const Type* intType = typeof(int); 392 | static const Type* longType = typeof(long); 393 | static const Type* longlongType = typeof(long long); 394 | static const Type* charType = typeof(char); 395 | static const Type* ucharType = typeof(unsigned char); 396 | static const Type* scharType = typeof(signed char); 397 | static const Type* uintType = typeof(unsigned int); 398 | static const Type* ulongType = typeof(unsigned long); 399 | static const Type* ulonglongType = typeof(unsigned long long); 400 | static const Type* floatType = typeof(float); 401 | static const Type* doubleType = typeof(double); 402 | static const Type* boolType = typeof(bool); 403 | static const Type* wcharType = typeof(wchar_t); 404 | static const Type* stringType = typeof(std::string); 405 | 406 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // to support std::to_string on mingw32 15 | #ifdef __MINGW32__ 16 | 17 | #include 18 | 19 | namespace std{ 20 | template 21 | string to_string(T t){ 22 | stringstream ss; 23 | ss << t; 24 | return ss.str(); 25 | } 26 | } 27 | 28 | #endif 29 | 30 | template 31 | struct AsType{ 32 | typedef B Value; 33 | }; 34 | 35 | class Type; 36 | 37 | struct Null{ 38 | static const Type* GetType(); 39 | }; 40 | 41 | template 42 | struct ReflectType{ 43 | static const Type* Value(){ 44 | //return Null::GetType(); 45 | return T::StaticType(); 46 | } 47 | }; 48 | 49 | template<> 50 | struct ReflectType{ 51 | static const Type* Value(){ 52 | return nullptr; 53 | } 54 | }; 55 | 56 | #define typeof(TYPE) ReflectType::Value() 57 | 58 | templateclass C> 59 | struct TemplateType; 60 | 61 | #define template_typeof(TYPE) TemplateType::Value() 62 | -------------------------------------------------------------------------------- /test_json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(test_json) 2 | 3 | set(TEST_SRC 4 | json11.cpp 5 | json11.hpp 6 | test_json.cpp 7 | ) 8 | 9 | include_directories(${HOME}/src) 10 | 11 | link_directories(${HOME}/lib) 12 | 13 | add_executable(test_json ${TEST_SRC}) 14 | add_dependencies(test_json lib) 15 | 16 | target_link_libraries(test_json reflection) 17 | 18 | set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin) 19 | -------------------------------------------------------------------------------- /test_json/json11.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013 Dropbox, Inc. 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | * THE SOFTWARE. 20 | */ 21 | 22 | #include "json11.hpp" 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace json11 { 29 | 30 | static const int max_depth = 200; 31 | 32 | using std::string; 33 | using std::vector; 34 | using std::map; 35 | using std::make_shared; 36 | using std::initializer_list; 37 | using std::move; 38 | 39 | /* * * * * * * * * * * * * * * * * * * * 40 | * Serialization 41 | */ 42 | 43 | static void dump(std::nullptr_t, string &out) { 44 | out += "null"; 45 | } 46 | 47 | static void dump(double value, string &out) { 48 | char buf[32]; 49 | sprintf(buf, "%.17g", value); 50 | out += buf; 51 | } 52 | 53 | static void dump(int value, string &out) { 54 | char buf[32]; 55 | sprintf(buf, "%d", value); 56 | out += buf; 57 | } 58 | 59 | static void dump(bool value, string &out) { 60 | out += value ? "true" : "false"; 61 | } 62 | 63 | static void dump(const string &value, string &out) { 64 | out += '"'; 65 | for (size_t i = 0; i < value.length(); i++) { 66 | const char ch = value[i]; 67 | if (ch == '\\') { 68 | out += "\\\\"; 69 | } 70 | else if (ch == '"') { 71 | out += "\\\""; 72 | } 73 | else if (ch == '\b') { 74 | out += "\\b"; 75 | } 76 | else if (ch == '\f') { 77 | out += "\\f"; 78 | } 79 | else if (ch == '\n') { 80 | out += "\\n"; 81 | } 82 | else if (ch == '\r') { 83 | out += "\\r"; 84 | } 85 | else if (ch == '\t') { 86 | out += "\\t"; 87 | } 88 | else if (static_cast(ch) <= 0x1f) { 89 | char buf[8]; 90 | sprintf(buf, "\\u%04x", ch); 91 | out += buf; 92 | } 93 | else if (static_cast(ch) == 0xe2 && static_cast(value[i + 1]) == 0x80 94 | && static_cast(value[i + 2]) == 0xa8) { 95 | out += "\\u2028"; 96 | i += 2; 97 | } 98 | else if (static_cast(ch) == 0xe2 && static_cast(value[i + 1]) == 0x80 99 | && static_cast(value[i + 2]) == 0xa9) { 100 | out += "\\u2029"; 101 | i += 2; 102 | } 103 | else { 104 | out += ch; 105 | } 106 | } 107 | out += '"'; 108 | } 109 | 110 | static void dump(const Json::array &values, string &out) { 111 | bool first = true; 112 | out += "["; 113 | for (auto &value : values) { 114 | if (!first) 115 | out += ", "; 116 | value.dump(out); 117 | first = false; 118 | } 119 | out += "]"; 120 | } 121 | 122 | static void dump(const Json::object &values, string &out) { 123 | bool first = true; 124 | out += "{"; 125 | for (const std::pair &kv : values) { 126 | if (!first) 127 | out += ", "; 128 | dump(kv.first, out); 129 | out += ": "; 130 | kv.second.dump(out); 131 | first = false; 132 | } 133 | out += "}"; 134 | } 135 | 136 | void Json::dump(string &out) const { 137 | m_ptr->dump(out); 138 | } 139 | 140 | /* * * * * * * * * * * * * * * * * * * * 141 | * Value wrappers 142 | */ 143 | 144 | template 145 | class Value : public JsonValue { 146 | protected: 147 | 148 | // Constructors 149 | explicit Value(const T &value) : m_value(value) {} 150 | explicit Value(T &&value) : m_value(move(value)) {} 151 | 152 | // Get type tag 153 | Json::Type type() const override { 154 | return tag; 155 | } 156 | 157 | // Comparisons 158 | bool equals(const JsonValue * other) const override { 159 | return m_value == static_cast *>(other)->m_value; 160 | } 161 | bool less(const JsonValue * other) const override { 162 | return m_value < static_cast *>(other)->m_value; 163 | } 164 | 165 | const T m_value; 166 | void dump(string &out) const override { json11::dump(m_value, out); } 167 | }; 168 | 169 | class JsonDouble final : public Value { 170 | double number_value() const override { return m_value; } 171 | int int_value() const override { return static_cast(m_value); } 172 | bool equals(const JsonValue * other) const override { return m_value == other->number_value(); } 173 | bool less(const JsonValue * other) const override { return m_value < other->number_value(); } 174 | public: 175 | explicit JsonDouble(double value) : Value(value) {} 176 | }; 177 | 178 | class JsonInt final : public Value { 179 | double number_value() const override { return m_value; } 180 | int int_value() const override { return m_value; } 181 | bool equals(const JsonValue * other) const override { return m_value == other->number_value(); } 182 | bool less(const JsonValue * other) const override { return m_value < other->number_value(); } 183 | public: 184 | explicit JsonInt(int value) : Value(value) {} 185 | }; 186 | 187 | class JsonBoolean final : public Value { 188 | bool bool_value() const override { return m_value; } 189 | public: 190 | explicit JsonBoolean(bool value) : Value(value) {} 191 | }; 192 | 193 | class JsonString final : public Value { 194 | const string &string_value() const override { return m_value; } 195 | public: 196 | explicit JsonString(const string &value) : Value(value) {} 197 | explicit JsonString(string &&value) : Value(move(value)) {} 198 | }; 199 | 200 | class JsonArray final : public Value { 201 | const Json::array &array_items() const override { return m_value; } 202 | const Json & operator[](size_t i) const override; 203 | public: 204 | explicit JsonArray(const Json::array &value) : Value(value) {} 205 | explicit JsonArray(Json::array &&value) : Value(move(value)) {} 206 | }; 207 | 208 | class JsonObject final : public Value { 209 | const Json::object &object_items() const override { return m_value; } 210 | const Json & operator[](const string &key) const override; 211 | public: 212 | explicit JsonObject(const Json::object &value) : Value(value) {} 213 | explicit JsonObject(Json::object &&value) : Value(move(value)) {} 214 | }; 215 | 216 | class JsonNull final : public Value { 217 | public: 218 | JsonNull() : Value(nullptr) {} 219 | }; 220 | 221 | /* * * * * * * * * * * * * * * * * * * * 222 | * Static globals - static-init-safe 223 | */ 224 | struct Statics { 225 | const std::shared_ptr null = make_shared(); 226 | const std::shared_ptr t = make_shared(true); 227 | const std::shared_ptr f = make_shared(false); 228 | const string empty_string; 229 | const vector empty_vector; 230 | const map empty_map; 231 | Statics() {} 232 | }; 233 | 234 | const Statics & statics() { 235 | static const Statics s{}; 236 | return s; 237 | } 238 | 239 | const Json & static_null() { 240 | // This has to be separate, not in Statics, because Json() accesses statics().null. 241 | static const Json json_null; 242 | return json_null; 243 | } 244 | 245 | /* * * * * * * * * * * * * * * * * * * * 246 | * Constructors 247 | */ 248 | 249 | Json::Json() : m_ptr(statics().null) {} 250 | Json::Json(std::nullptr_t) : m_ptr(statics().null) {} 251 | Json::Json(double value) : m_ptr(make_shared(value)) {} 252 | Json::Json(int value) : m_ptr(make_shared(value)) {} 253 | Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {} 254 | Json::Json(const string &value) : m_ptr(make_shared(value)) {} 255 | Json::Json(string &&value) : m_ptr(make_shared(move(value))) {} 256 | Json::Json(const char * value) : m_ptr(make_shared(value)) {} 257 | Json::Json(const Json::array &values) : m_ptr(make_shared(values)) {} 258 | Json::Json(Json::array &&values) : m_ptr(make_shared(move(values))) {} 259 | Json::Json(const Json::object &values) : m_ptr(make_shared(values)) {} 260 | Json::Json(Json::object &&values) : m_ptr(make_shared(move(values))) {} 261 | 262 | /* * * * * * * * * * * * * * * * * * * * 263 | * Accessors 264 | */ 265 | 266 | Json::Type Json::type() const { return m_ptr->type(); } 267 | double Json::number_value() const { return m_ptr->number_value(); } 268 | int Json::int_value() const { return m_ptr->int_value(); } 269 | bool Json::bool_value() const { return m_ptr->bool_value(); } 270 | const string & Json::string_value() const { return m_ptr->string_value(); } 271 | const vector & Json::array_items() const { return m_ptr->array_items(); } 272 | const map & Json::object_items() const { return m_ptr->object_items(); } 273 | const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; } 274 | const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; } 275 | 276 | double JsonValue::number_value() const { return 0; } 277 | int JsonValue::int_value() const { return 0; } 278 | bool JsonValue::bool_value() const { return false; } 279 | const string & JsonValue::string_value() const { return statics().empty_string; } 280 | const vector & JsonValue::array_items() const { return statics().empty_vector; } 281 | const map & JsonValue::object_items() const { return statics().empty_map; } 282 | const Json & JsonValue::operator[] (size_t) const { return static_null(); } 283 | const Json & JsonValue::operator[] (const string &) const { return static_null(); } 284 | 285 | const Json & JsonObject::operator[] (const string &key) const { 286 | auto iter = m_value.find(key); 287 | return (iter == m_value.end()) ? static_null() : iter->second; 288 | } 289 | const Json & JsonArray::operator[] (size_t i) const { 290 | if (i >= m_value.size()) return static_null(); 291 | else return m_value[i]; 292 | } 293 | 294 | /* * * * * * * * * * * * * * * * * * * * 295 | * Comparison 296 | */ 297 | 298 | bool Json::operator== (const Json &other) const { 299 | if (m_ptr->type() != other.m_ptr->type()) 300 | return false; 301 | 302 | return m_ptr->equals(other.m_ptr.get()); 303 | } 304 | 305 | bool Json::operator< (const Json &other) const { 306 | if (m_ptr->type() != other.m_ptr->type()) 307 | return m_ptr->type() < other.m_ptr->type(); 308 | 309 | return m_ptr->less(other.m_ptr.get()); 310 | } 311 | 312 | /* * * * * * * * * * * * * * * * * * * * 313 | * Parsing 314 | */ 315 | 316 | /* esc(c) 317 | * 318 | * Format char c suitable for printing in an error message. 319 | */ 320 | static inline string esc(char c) { 321 | char buf[12]; 322 | if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { 323 | sprintf(buf, "'%c' (%d)", c, c); 324 | } 325 | else { 326 | sprintf(buf, "(%d)", c); 327 | } 328 | return string(buf); 329 | } 330 | 331 | static inline bool in_range(long x, long lower, long upper) { 332 | return (x >= lower && x <= upper); 333 | } 334 | 335 | /* JsonParser 336 | * 337 | * Object that tracks all state of an in-progress parse. 338 | */ 339 | struct JsonParser { 340 | 341 | /* State 342 | */ 343 | const string &str; 344 | size_t i; 345 | string &err; 346 | bool failed; 347 | 348 | /* fail(msg, err_ret = Json()) 349 | * 350 | * Mark this parse as failed. 351 | */ 352 | Json fail(string &&msg) { 353 | return fail(move(msg), Json()); 354 | } 355 | 356 | template 357 | T fail(string &&msg, const T err_ret) { 358 | if (!failed) 359 | err = std::move(msg); 360 | failed = true; 361 | return err_ret; 362 | } 363 | 364 | /* consume_whitespace() 365 | * 366 | * Advance until the current character is non-whitespace. 367 | */ 368 | void consume_whitespace() { 369 | while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t') 370 | i++; 371 | } 372 | 373 | /* get_next_token() 374 | * 375 | * Return the next non-whitespace character. If the end of the input is reached, 376 | * flag an error and return 0. 377 | */ 378 | char get_next_token() { 379 | consume_whitespace(); 380 | if (i == str.size()) 381 | return fail("unexpected end of input", 0); 382 | 383 | return str[i++]; 384 | } 385 | 386 | /* encode_utf8(pt, out) 387 | * 388 | * Encode pt as UTF-8 and add it to out. 389 | */ 390 | void encode_utf8(long pt, string & out) { 391 | if (pt < 0) 392 | return; 393 | 394 | if (pt < 0x80) { 395 | out += pt; 396 | } 397 | else if (pt < 0x800) { 398 | out += (pt >> 6) | 0xC0; 399 | out += (pt & 0x3F) | 0x80; 400 | } 401 | else if (pt < 0x10000) { 402 | out += (pt >> 12) | 0xE0; 403 | out += ((pt >> 6) & 0x3F) | 0x80; 404 | out += (pt & 0x3F) | 0x80; 405 | } 406 | else { 407 | out += (pt >> 18) | 0xF0; 408 | out += ((pt >> 12) & 0x3F) | 0x80; 409 | out += ((pt >> 6) & 0x3F) | 0x80; 410 | out += (pt & 0x3F) | 0x80; 411 | } 412 | } 413 | 414 | /* parse_string() 415 | * 416 | * Parse a string, starting at the current position. 417 | */ 418 | string parse_string() { 419 | string out; 420 | long last_escaped_codepoint = -1; 421 | while (true) { 422 | if (i == str.size()) 423 | return fail("unexpected end of input in string", ""); 424 | 425 | char ch = str[i++]; 426 | 427 | if (ch == '"') { 428 | encode_utf8(last_escaped_codepoint, out); 429 | return out; 430 | } 431 | 432 | if (in_range(ch, 0, 0x1f)) 433 | return fail("unescaped " + esc(ch) + " in string", ""); 434 | 435 | // The usual case: non-escaped characters 436 | if (ch != '\\') { 437 | encode_utf8(last_escaped_codepoint, out); 438 | last_escaped_codepoint = -1; 439 | out += ch; 440 | continue; 441 | } 442 | 443 | // Handle escapes 444 | if (i == str.size()) 445 | return fail("unexpected end of input in string", ""); 446 | 447 | ch = str[i++]; 448 | 449 | if (ch == 'u') { 450 | // Extract 4-byte escape sequence 451 | string esc = str.substr(i, 4); 452 | for (int j = 0; j < 4; j++) { 453 | if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') 454 | && !in_range(esc[j], '0', '9')) 455 | return fail("bad \\u escape: " + esc, ""); 456 | } 457 | 458 | long codepoint = strtol(esc.data(), nullptr, 16); 459 | 460 | // JSON specifies that characters outside the BMP shall be encoded as a pair 461 | // of 4-hex-digit \u escapes encoding their surrogate pair components. Check 462 | // whether we're in the middle of such a beast: the previous codepoint was an 463 | // escaped lead (high) surrogate, and this is a trail (low) surrogate. 464 | if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) 465 | && in_range(codepoint, 0xDC00, 0xDFFF)) { 466 | // Reassemble the two surrogate pairs into one astral-plane character, per 467 | // the UTF-16 algorithm. 468 | encode_utf8((((last_escaped_codepoint - 0xD800) << 10) 469 | | (codepoint - 0xDC00)) + 0x10000, out); 470 | last_escaped_codepoint = -1; 471 | } 472 | else { 473 | encode_utf8(last_escaped_codepoint, out); 474 | last_escaped_codepoint = codepoint; 475 | } 476 | 477 | i += 4; 478 | continue; 479 | } 480 | 481 | encode_utf8(last_escaped_codepoint, out); 482 | last_escaped_codepoint = -1; 483 | 484 | if (ch == 'b') { 485 | out += '\b'; 486 | } 487 | else if (ch == 'f') { 488 | out += '\f'; 489 | } 490 | else if (ch == 'n') { 491 | out += '\n'; 492 | } 493 | else if (ch == 'r') { 494 | out += '\r'; 495 | } 496 | else if (ch == 't') { 497 | out += '\t'; 498 | } 499 | else if (ch == '"' || ch == '\\' || ch == '/') { 500 | out += ch; 501 | } 502 | else { 503 | return fail("invalid escape character " + esc(ch), ""); 504 | } 505 | } 506 | } 507 | 508 | /* parse_number() 509 | * 510 | * Parse a double. 511 | */ 512 | Json parse_number() { 513 | size_t start_pos = i; 514 | 515 | if (str[i] == '-') 516 | i++; 517 | 518 | // Integer part 519 | if (str[i] == '0') { 520 | i++; 521 | if (in_range(str[i], '0', '9')) 522 | return fail("leading 0s not permitted in numbers"); 523 | } 524 | else if (in_range(str[i], '1', '9')) { 525 | i++; 526 | while (in_range(str[i], '0', '9')) 527 | i++; 528 | } 529 | else { 530 | return fail("invalid " + esc(str[i]) + " in number"); 531 | } 532 | 533 | if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' 534 | && (i - start_pos) <= static_cast(std::numeric_limits::digits10)) { 535 | return std::atoi(str.c_str() + start_pos); 536 | } 537 | 538 | // Decimal part 539 | if (str[i] == '.') { 540 | i++; 541 | if (!in_range(str[i], '0', '9')) 542 | return fail("at least one digit required in fractional part"); 543 | 544 | while (in_range(str[i], '0', '9')) 545 | i++; 546 | } 547 | 548 | // Exponent part 549 | if (str[i] == 'e' || str[i] == 'E') { 550 | i++; 551 | 552 | if (str[i] == '+' || str[i] == '-') 553 | i++; 554 | 555 | if (!in_range(str[i], '0', '9')) 556 | return fail("at least one digit required in exponent"); 557 | 558 | while (in_range(str[i], '0', '9')) 559 | i++; 560 | } 561 | 562 | return std::atof(str.c_str() + start_pos); 563 | } 564 | 565 | /* expect(str, res) 566 | * 567 | * Expect that 'str' starts at the character that was just read. If it does, advance 568 | * the input and return res. If not, flag an error. 569 | */ 570 | Json expect(const string &expected, Json res) { 571 | assert(i != 0); 572 | i--; 573 | if (str.compare(i, expected.length(), expected) == 0) { 574 | i += expected.length(); 575 | return res; 576 | } 577 | else { 578 | return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length())); 579 | } 580 | } 581 | 582 | /* parse_json() 583 | * 584 | * Parse a JSON object. 585 | */ 586 | Json parse_json(int depth) { 587 | if (depth > max_depth) { 588 | return fail("exceeded maximum nesting depth"); 589 | } 590 | 591 | char ch = get_next_token(); 592 | if (failed) 593 | return Json(); 594 | 595 | if (ch == '-' || (ch >= '0' && ch <= '9')) { 596 | i--; 597 | return parse_number(); 598 | } 599 | 600 | if (ch == 't') 601 | return expect("true", true); 602 | 603 | if (ch == 'f') 604 | return expect("false", false); 605 | 606 | if (ch == 'n') 607 | return expect("null", Json()); 608 | 609 | if (ch == '"') 610 | return parse_string(); 611 | 612 | if (ch == '{') { 613 | map data; 614 | ch = get_next_token(); 615 | if (ch == '}') 616 | return data; 617 | 618 | while (1) { 619 | if (ch != '"') 620 | return fail("expected '\"' in object, got " + esc(ch)); 621 | 622 | string key = parse_string(); 623 | if (failed) 624 | return Json(); 625 | 626 | ch = get_next_token(); 627 | if (ch != ':') 628 | return fail("expected ':' in object, got " + esc(ch)); 629 | 630 | data[std::move(key)] = parse_json(depth + 1); 631 | if (failed) 632 | return Json(); 633 | 634 | ch = get_next_token(); 635 | if (ch == '}') 636 | break; 637 | if (ch != ',') 638 | return fail("expected ',' in object, got " + esc(ch)); 639 | 640 | ch = get_next_token(); 641 | } 642 | return data; 643 | } 644 | 645 | if (ch == '[') { 646 | vector data; 647 | ch = get_next_token(); 648 | if (ch == ']') 649 | return data; 650 | 651 | while (1) { 652 | i--; 653 | data.push_back(parse_json(depth + 1)); 654 | if (failed) 655 | return Json(); 656 | 657 | ch = get_next_token(); 658 | if (ch == ']') 659 | break; 660 | if (ch != ',') 661 | return fail("expected ',' in list, got " + esc(ch)); 662 | 663 | ch = get_next_token(); 664 | (void)ch; 665 | } 666 | return data; 667 | } 668 | 669 | return fail("expected value, got " + esc(ch)); 670 | } 671 | }; 672 | 673 | Json Json::parse(const string &in, string &err) { 674 | JsonParser parser{ in, 0, err, false }; 675 | Json result = parser.parse_json(0); 676 | 677 | // Check for any trailing garbage 678 | parser.consume_whitespace(); 679 | if (parser.i != in.size()) 680 | return parser.fail("unexpected trailing " + esc(in[parser.i])); 681 | 682 | return result; 683 | } 684 | 685 | // Documented in json11.hpp 686 | vector Json::parse_multi(const string &in, string &err) { 687 | JsonParser parser{ in, 0, err, false }; 688 | 689 | vector json_vec; 690 | while (parser.i != in.size() && !parser.failed) { 691 | json_vec.push_back(parser.parse_json(0)); 692 | // Check for another object 693 | parser.consume_whitespace(); 694 | } 695 | return json_vec; 696 | } 697 | 698 | /* * * * * * * * * * * * * * * * * * * * 699 | * Shape-checking 700 | */ 701 | 702 | bool Json::has_shape(const shape & types, string & err) const { 703 | if (!is_object()) { 704 | err = "expected JSON object, got " + dump(); 705 | return false; 706 | } 707 | 708 | for (auto & item : types) { 709 | if ((*this)[item.first].type() != item.second) { 710 | err = "bad type for " + item.first + " in " + dump(); 711 | return false; 712 | } 713 | } 714 | 715 | return true; 716 | } 717 | 718 | } // namespace json11 -------------------------------------------------------------------------------- /test_json/json11.hpp: -------------------------------------------------------------------------------- 1 | /* json11 2 | * 3 | * json11 is a tiny JSON library for C++11, providing JSON parsing and serialization. 4 | * 5 | * The core object provided by the library is json11::Json. A Json object represents any JSON 6 | * value: null, bool, number (int or double), string (std::string), array (std::vector), or 7 | * object (std::map). 8 | * 9 | * Json objects act like values: they can be assigned, copied, moved, compared for equality or 10 | * order, etc. There are also helper methods Json::dump, to serialize a Json to a string, and 11 | * Json::parse (static) to parse a std::string as a Json object. 12 | * 13 | * Internally, the various types of Json object are represented by the JsonValue class 14 | * hierarchy. 15 | * 16 | * A note on numbers - JSON specifies the syntax of number formatting but not its semantics, 17 | * so some JSON implementations distinguish between integers and floating-point numbers, while 18 | * some don't. In json11, we choose the latter. Because some JSON implementations (namely 19 | * Javascript itself) treat all numbers as the same type, distinguishing the two leads 20 | * to JSON that will be *silently* changed by a round-trip through those implementations. 21 | * Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also 22 | * provides integer helpers. 23 | * 24 | * Fortunately, double-precision IEEE754 ('double') can precisely store any integer in the 25 | * range +/-2^53, which includes every 'int' on most systems. (Timestamps often use int64 26 | * or long long to avoid the Y2038K problem; a double storing microseconds since some epoch 27 | * will be exact for +/- 275 years.) 28 | */ 29 | 30 | /* Copyright (c) 2013 Dropbox, Inc. 31 | * 32 | * Permission is hereby granted, free of charge, to any person obtaining a copy 33 | * of this software and associated documentation files (the "Software"), to deal 34 | * in the Software without restriction, including without limitation the rights 35 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 36 | * copies of the Software, and to permit persons to whom the Software is 37 | * furnished to do so, subject to the following conditions: 38 | * 39 | * The above copyright notice and this permission notice shall be included in 40 | * all copies or substantial portions of the Software. 41 | * 42 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 44 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 45 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 46 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 47 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 48 | * THE SOFTWARE. 49 | */ 50 | 51 | #pragma once 52 | 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | 59 | namespace json11 { 60 | 61 | class JsonValue; 62 | 63 | class Json final { 64 | public: 65 | // Types 66 | enum Type { 67 | NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT 68 | }; 69 | 70 | // Array and object typedefs 71 | typedef std::vector array; 72 | typedef std::map object; 73 | 74 | // Constructors for the various types of JSON value. 75 | Json(); // NUL 76 | Json(std::nullptr_t); // NUL 77 | Json(double value); // NUMBER 78 | Json(int value); // NUMBER 79 | Json(bool value); // BOOL 80 | Json(const std::string &value); // STRING 81 | Json(std::string &&value); // STRING 82 | Json(const char * value); // STRING 83 | Json(const array &values); // ARRAY 84 | Json(array &&values); // ARRAY 85 | Json(const object &values); // OBJECT 86 | Json(object &&values); // OBJECT 87 | 88 | // Implicit constructor: anything with a to_json() function. 89 | template 90 | Json(const T & t) : Json(t.to_json()) {} 91 | 92 | // Implicit constructor: map-like objects (std::map, std::unordered_map, etc) 93 | template ::value 95 | && std::is_constructible::value, 96 | int>::type = 0> 97 | Json(const M & m) : Json(object(m.begin(), m.end())) {} 98 | 99 | // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc) 100 | template ::value, 102 | int>::type = 0> 103 | Json(const V & v) : Json(array(v.begin(), v.end())) {} 104 | 105 | // This prevents Json(some_pointer) from accidentally producing a bool. Use 106 | // Json(bool(some_pointer)) if that behavior is desired. 107 | Json(void *) = delete; 108 | 109 | // Accessors 110 | Type type() const; 111 | 112 | bool is_null() const { return type() == NUL; } 113 | bool is_number() const { return type() == NUMBER; } 114 | bool is_bool() const { return type() == BOOL; } 115 | bool is_string() const { return type() == STRING; } 116 | bool is_array() const { return type() == ARRAY; } 117 | bool is_object() const { return type() == OBJECT; } 118 | 119 | // Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not 120 | // distinguish between integer and non-integer numbers - number_value() and int_value() 121 | // can both be applied to a NUMBER-typed object. 122 | double number_value() const; 123 | int int_value() const; 124 | 125 | // Return the enclosed value if this is a boolean, false otherwise. 126 | bool bool_value() const; 127 | // Return the enclosed string if this is a string, "" otherwise. 128 | const std::string &string_value() const; 129 | // Return the enclosed std::vector if this is an array, or an empty vector otherwise. 130 | const array &array_items() const; 131 | // Return the enclosed std::map if this is an object, or an empty map otherwise. 132 | const object &object_items() const; 133 | 134 | // Return a reference to arr[i] if this is an array, Json() otherwise. 135 | const Json & operator[](size_t i) const; 136 | // Return a reference to obj[key] if this is an object, Json() otherwise. 137 | const Json & operator[](const std::string &key) const; 138 | 139 | // Serialize. 140 | void dump(std::string &out) const; 141 | std::string dump() const { 142 | std::string out; 143 | dump(out); 144 | return out; 145 | } 146 | 147 | // Parse. If parse fails, return Json() and assign an error message to err. 148 | static Json parse(const std::string & in, std::string & err); 149 | static Json parse(const char * in, std::string & err) { 150 | if (in) { 151 | return parse(std::string(in), err); 152 | } 153 | else { 154 | err = "null input"; 155 | return nullptr; 156 | } 157 | } 158 | // Parse multiple objects, concatenated or separated by whitespace 159 | static std::vector parse_multi(const std::string & in, std::string & err); 160 | 161 | bool operator== (const Json &rhs) const; 162 | bool operator< (const Json &rhs) const; 163 | bool operator!= (const Json &rhs) const { return !(*this == rhs); } 164 | bool operator<= (const Json &rhs) const { return !(rhs < *this); } 165 | bool operator>(const Json &rhs) const { return (rhs < *this); } 166 | bool operator>= (const Json &rhs) const { return !(*this < rhs); } 167 | 168 | /* has_shape(types, err) 169 | * 170 | * Return true if this is a JSON object and, for each item in types, has a field of 171 | * the given type. If not, return false and set err to a descriptive message. 172 | */ 173 | typedef std::initializer_list> shape; 174 | bool has_shape(const shape & types, std::string & err) const; 175 | 176 | private: 177 | std::shared_ptr m_ptr; 178 | }; 179 | 180 | // Internal class hierarchy - JsonValue objects are not exposed to users of this API. 181 | class JsonValue { 182 | protected: 183 | friend class Json; 184 | friend class JsonInt; 185 | friend class JsonDouble; 186 | virtual Json::Type type() const = 0; 187 | virtual bool equals(const JsonValue * other) const = 0; 188 | virtual bool less(const JsonValue * other) const = 0; 189 | virtual void dump(std::string &out) const = 0; 190 | virtual double number_value() const; 191 | virtual int int_value() const; 192 | virtual bool bool_value() const; 193 | virtual const std::string &string_value() const; 194 | virtual const Json::array &array_items() const; 195 | virtual const Json &operator[](size_t i) const; 196 | virtual const Json::object &object_items() const; 197 | virtual const Json &operator[](const std::string &key) const; 198 | virtual ~JsonValue() {} 199 | }; 200 | 201 | } // namespace json11 -------------------------------------------------------------------------------- /test_json/test_json.cpp: -------------------------------------------------------------------------------- 1 | #include "json11.hpp" 2 | #include "reflection.h" 3 | 4 | #define THROW_EXCEPTION(name, msg) { name ex; ex.What() = msg; ex.Where() = std::string(__FILE__ " (" + std::to_string(__LINE__) + ")"); throw ex; } 5 | 6 | using namespace std; 7 | 8 | class PhoneNumber{ 9 | BEGIN_TYPE(PhoneNumber) 10 | FIELDS(FIELD(&PhoneNumber::areaCode), FIELD(&PhoneNumber::number)) 11 | CTORS(DEFAULT_CTOR(PhoneNumber), CTOR(PhoneNumber, const std::string&, const std::string&)) 12 | METHODS(METHOD(&PhoneNumber::ToString)) 13 | END_TYPE 14 | public: 15 | std::string areaCode; 16 | std::string number; 17 | 18 | PhoneNumber() {} 19 | PhoneNumber(const std::string& areaCode, const std::string& number) : areaCode(areaCode), number(number) {} 20 | 21 | std::string ToString() const{ 22 | return areaCode + " " + number; 23 | } 24 | }; 25 | 26 | REFLECT_ENUM(Sex, Secret, Male, Female) 27 | 28 | class Person{ 29 | BEGIN_TYPE(Person) 30 | FIELDS(FIELD(&Person::name), FIELD(&Person::height), FIELD(&Person::sex), FIELD(&Person::phoneNumber), FIELD(&Person::totalNumber)) 31 | CTORS(DEFAULT_CTOR(Person), CTOR(Person, const std::string&, float, Sex)) 32 | METHODS(METHOD(&Person::GetName), METHOD(&Person::SetName), METHOD(&Person::Name), METHOD(&Person::GetHeight), METHOD(&Person::GetSex), METHOD(&Person::GetPhoneNumber), METHOD(&Person::SetPhoneNumber), METHOD(&Person::GetTotalNumber), METHOD(&Person::IsMale), METHOD(&Person::IsFemale)) 33 | END_TYPE 34 | protected: 35 | std::string name; 36 | float height; 37 | Sex sex; 38 | PhoneNumber phoneNumber; 39 | 40 | static int totalNumber; 41 | 42 | public: 43 | Person(const std::string& name, float height, Sex sex) 44 | : name(name), height(height), sex(sex) { 45 | totalNumber++; 46 | } 47 | 48 | Person() : Person("Unnamed", 0, Sex::Secret) { } 49 | 50 | const std::string& GetName() const{ 51 | return name; 52 | } 53 | 54 | void SetName(const std::string& name){ 55 | this->name = name; 56 | } 57 | 58 | std::string& Name() { 59 | return name; 60 | } 61 | 62 | float GetHeight() const{ 63 | return height; 64 | } 65 | 66 | Sex GetSex() const{ 67 | return sex; 68 | } 69 | 70 | bool IsMale() const{ 71 | return sex == Sex::Male; 72 | } 73 | 74 | bool IsFemale() const{ 75 | return sex == Sex::Female; 76 | } 77 | 78 | const PhoneNumber& GetPhoneNumber(){ 79 | return phoneNumber; 80 | } 81 | 82 | void SetPhoneNumber(const PhoneNumber& phoneNumber){ 83 | this->phoneNumber = phoneNumber; 84 | } 85 | 86 | static int GetTotalNumber(){ 87 | return totalNumber; 88 | } 89 | 90 | }; 91 | 92 | int Person::totalNumber = 0; 93 | 94 | using namespace json11; 95 | 96 | Any FromJson(const Json& json, const Type* type){ 97 | #define XX(T) if (type == typeof(T)) { return T(json.number_value()); } 98 | XX(int8_t); 99 | XX(int16_t); 100 | XX(int32_t); 101 | XX(int64_t); 102 | XX(uint8_t); 103 | XX(uint16_t); 104 | XX(uint32_t); 105 | XX(uint64_t); 106 | XX(float); 107 | XX(double); 108 | if (type == typeof(bool)){ return json.bool_value(); } 109 | if (type == typeof(std::string)) { return json.string_value(); } 110 | if (type->IsEnum()){ return Enum::GetValue(type, json.string_value()); } 111 | 112 | Any obj = type->GetConstructor()->Invoke(); 113 | for (auto& i : json.object_items()){ 114 | auto field = type->GetField(i.first); 115 | if (!field) THROW_EXCEPTION(FieldNotFound, "field '" + field->GetName() + "' not found in class '" + type->GetName() + "'"); 116 | auto value = FromJson(i.second, field->GetType().GetType()); 117 | for (int i = value.GetType().PointerCount() - field->GetType().PointerCount(); i > 0; i--) 118 | value = *value; 119 | field->Set(obj, value); 120 | } 121 | return obj; 122 | } 123 | 124 | template 125 | std::shared_ptr FromJson(const Json& json){ 126 | return std::shared_ptr((T*)FromJson(json, typeof(T))); 127 | } 128 | 129 | class JsonError : public Exception{}; 130 | 131 | template 132 | std::shared_ptr FromJson(const std::string& jsonText){ 133 | std::string err; 134 | auto json = Json::parse(jsonText, err); 135 | if (err.empty()) 136 | return FromJson(json); 137 | 138 | THROW_EXCEPTION(JsonError, "failed to parse json: " + jsonText); 139 | } 140 | 141 | template 142 | std::shared_ptr FromJson(const char* jsonText){ 143 | return FromJson(std::string(jsonText)); 144 | } 145 | 146 | std::string ToJson(void* obj, const Type* type){ 147 | std::stringstream ss; 148 | 149 | if (obj == nullptr){ 150 | ss << "null"; 151 | } 152 | else{ 153 | ss << "{ "; 154 | int i = 0; 155 | for (auto f : type->GetMemberFields()){ 156 | if (i++ > 0) ss << ", "; 157 | ss << "\"" << f->GetName() << "\" : "; 158 | 159 | auto ft = f->GetType(); 160 | if (ft.IsNumber() || ft.IsBool()) 161 | ss << f->Get(obj).ToString(); 162 | else if (ft.IsString()) 163 | ss << "\"" << f->Get(obj).ToString() << "\""; 164 | else if (ft.IsEnum()) 165 | ss << "\"" << Enum::GetName(ft.GetType(), (int64_t)f->Get(obj)) << "\""; 166 | else 167 | ss << ToJson((void*)f->Get(obj), ft.GetType()); 168 | } 169 | ss << " }"; 170 | } 171 | 172 | return ss.str(); 173 | } 174 | 175 | template 176 | std::string ToJson(T& obj){ 177 | auto type = qualified_typeof(T).GetType(); 178 | return ToJson(&obj, qualified_typeof(T).GetType()); 179 | } 180 | 181 | template 182 | std::string ToJson(T* obj){ 183 | return ToJson(obj, qualified_typeof(T).GetType()); 184 | } 185 | 186 | template 187 | std::string ToJson(std::shared_ptr obj){ 188 | return ToJson(*obj); 189 | } 190 | 191 | int main(){ 192 | try{ 193 | auto p = FromJson(R"({"name":"John", "height":1.7, "sex":"Female", "phoneNumber" : {"areaCode":"+86", "number":"13888888888"}})"); 194 | auto newPhone = Type::GetType("PhoneNumber")->GetConstructor({qualified_typeof(const std::string&), qualified_typeof(const std::string&)})->Invoke(std::string("+86"), std::string("13000000000")); 195 | p->GetType()->GetMethod("SetPhoneNumber")->Invoke(p.get(), newPhone); 196 | std::cout << ToJson(p) << std::endl; 197 | PhoneNumber phone = p->GetType()->GetMethod("GetPhoneNumber")->Invoke(p.get()); 198 | std::cout << phone.ToString() << endl; 199 | Sex sex = p->GetType()->GetField("sex")->Get(p.get()); 200 | std::cout << Enum::GetName(sex) << std::endl; 201 | 202 | std::cout << typeof(Person)->GetDescription() << std::endl; 203 | std::cout << typeof(PhoneNumber)->GetDescription() << std::endl; 204 | 205 | auto type1 = p->GetType(); 206 | auto type2 = typeof(Person); 207 | auto type3 = Person::StaticType(); 208 | auto type4 = Type::GetType("Person"); 209 | 210 | short i = 1; 211 | Any any1(i); 212 | Any any2(any1); 213 | cout << (int)any1 << ", " << (int)any2 << endl; 214 | any2 = any1; 215 | cout << (int)any1 << ", " << (int)any2 << endl; 216 | any2 = Any(2); 217 | cout << (int)any2 << endl; 218 | any2 = 1; 219 | cout << (int)any2 << endl; 220 | 221 | 222 | #define TEST(x) cout << Any(x).GetType().ToString() << " : " << Any(x).Cast() << endl; 223 | TEST(i); 224 | TEST(3.14); 225 | cout << Any(1.5).Cast() << endl; 226 | cout << Any("foo").GetType().ToString() << " : " << Any("foo").Cast() << endl; 227 | TEST(std::string("bar")); 228 | TEST(make_shared("asdfgh12345")); 229 | string a = "foo"; 230 | string& ref = a; 231 | int b = 123; 232 | TEST(b); 233 | auto any = Any(a); 234 | any.Cast().append("_modified"); 235 | Any aa = Any(a); 236 | cout << any.GetType().ToString() << " : " << any.Cast() << ", " << ref << endl; 237 | aa.Cast().append("123"); 238 | cout << aa.Cast() << endl; 239 | //TEST(ref); 240 | } 241 | catch (const Exception& ex){ 242 | std::cout << "error: " << ex.What() << " at: " << ex.Where() << std::endl; 243 | } 244 | 245 | system("pause"); 246 | 247 | return 0; 248 | } --------------------------------------------------------------------------------