diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h index 353bce4b01d06c353d7e20da9728844e700aa210..bd128c9569d62a54505e35c7bfa99e439db8fa50 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h @@ -55,6 +55,7 @@ IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rap IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, double); IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, bool); IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::string&); +IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const char*); IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::vector<T>& ts) { @@ -102,104 +103,12 @@ IPAACA_HEADER_EXPORT class PayloadDocumentEntry//{{{ IPAACA_HEADER_EXPORT inline ~PayloadDocumentEntry() { IPAACA_INFO("") } //IPAACA_HEADER_EXPORT PayloadDocumentEntry(const std::string& source): modified(false), json_source(source), {}; IPAACA_HEADER_EXPORT std::string to_json_string_representation(); - static std::shared_ptr<PayloadDocumentEntry> from_json_string_representation(const std::string& input); - static std::shared_ptr<PayloadDocumentEntry> create_null(); - std::shared_ptr<PayloadDocumentEntry> clone(); + IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> from_json_string_representation(const std::string& input); + IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> create_null(); + IPAACA_HEADER_EXPORT std::shared_ptr<PayloadDocumentEntry> clone(); + IPAACA_HEADER_EXPORT rapidjson::Value& get_or_create_nested_value_from_proxy_path(PayloadEntryProxy* pep); typedef std::shared_ptr<PayloadDocumentEntry> ptr; }; -//}}} -IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ -{ - protected: - //IPAACA_MEMBER_VAR_EXPORT rapidjson::Document* _json_parent_node; - //IPAACA_MEMBER_VAR_EXPORT rapidjson::Document* _json_node; - IPAACA_MEMBER_VAR_EXPORT Payload* _payload; - IPAACA_MEMBER_VAR_EXPORT std::string _key; - // - // new json stuff / hierarchical navigation - // - PayloadEntryProxy* parent; // parent (up to document root -> then null) - PayloadDocumentEntry::ptr document_entry; // contains lock and json Doc - bool existent; // whether Value exists already (or blindly navigated) - bool addressed_as_array; // whether long or string navigation used - long addressed_index; - std::string addressed_key; - /// currently navigated value in json tree (or a new Null value) - rapidjson::Value* json_value; - protected: - IPAACA_HEADER_EXPORT void connect_to_existing_parents(); - public: - // constructor to create a new top-most parent proxy (from a payload key) - IPAACA_HEADER_EXPORT PayloadEntryProxy(Payload* payload, const std::string& key); - // constructors for navigation through objects - IPAACA_HEADER_EXPORT PayloadEntryProxy(PayloadEntryProxy* parent, const std::string& addressed_key); - IPAACA_HEADER_EXPORT PayloadEntryProxy(PayloadEntryProxy* parent, size_t addressed_index); - public: - IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](size_t index); // array-style navigation - IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const std::string& key); - // - IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const std::string& value); - IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const char* value); - IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(double value); - IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(bool value); - - IPAACA_HEADER_EXPORT operator std::string(); - IPAACA_HEADER_EXPORT operator long(); - IPAACA_HEADER_EXPORT operator double(); - IPAACA_HEADER_EXPORT operator bool(); - IPAACA_HEADER_EXPORT template<typename Inner> operator std::vector<Inner>() { - if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError(); - std::vector<Inner> result; - for (auto it = json_value->Begin(); it != json_value->End(); ++it) { - result.push_back( json_value_cast<Inner>(*it) ); - } - return result; - } - IPAACA_HEADER_EXPORT template<typename Inner> operator std::list<Inner>() { - if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError(); - std::list<Inner> result; - for (auto it = json_value->Begin(); it != json_value->End(); ++it) { - result.push_back( json_value_cast<Inner>(*it) ); - } - return result; - } - IPAACA_HEADER_EXPORT template<typename Inner> operator std::map<std::string, Inner>() { - if ((!json_value) || (!json_value->IsObject())) throw PayloadAddressingError(); - std::map<std::string, Inner> result; - for (auto it = json_value->MemberBegin(); it != json_value->MemberEnd(); ++it) { - result[std::string(it->name.GetString())] = json_value_cast<Inner>(it->value); - } - return result; - } - // FIXME why are these needed again? - IPAACA_HEADER_EXPORT std::string to_str(); - //long to_int() { return operator long(); ; - IPAACA_HEADER_EXPORT long to_long(); - IPAACA_HEADER_EXPORT double to_float(); - IPAACA_HEADER_EXPORT bool to_bool(); - // getters - IPAACA_HEADER_EXPORT template<typename T> T get() { return json_value_cast<T>(json_value); } // specializations below - // setters - IPAACA_HEADER_EXPORT template<typename T> PayloadEntryProxy& set(T t); - /*{ - pack_into_json_value<T>(t); - connect_to_existing_parents(); - _payload->set(key, document_entry->document); - }*/ -}; -// Available interpretations of payload entries (or children thereof) below. -// Usage of standard complex data structures (vector etc.) currently entails -// casting all entries to a uniform type (a-priori choice: std::string). -/* -IPAACA_HEADER_EXPORT template<> long PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> double PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> bool PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> std::string PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> std::list<std::string> PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get(); -*/ - //}}} /* @@ -300,4 +209,110 @@ IPAACA_HEADER_EXPORT class Payload//{{{ typedef boost::shared_ptr<Payload> ptr; };//}}} +IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ +{ + protected: + public: + //IPAACA_MEMBER_VAR_EXPORT rapidjson::Document* _json_parent_node; + //IPAACA_MEMBER_VAR_EXPORT rapidjson::Document* _json_node; + IPAACA_MEMBER_VAR_EXPORT Payload* _payload; + IPAACA_MEMBER_VAR_EXPORT std::string _key; + // + // new json stuff / hierarchical navigation + // + IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* parent; // parent (up to document root -> then null) + IPAACA_MEMBER_VAR_EXPORT PayloadDocumentEntry::ptr document_entry; // contains lock and json Doc + IPAACA_MEMBER_VAR_EXPORT bool existent; // whether Value exists already (or blindly navigated) + IPAACA_MEMBER_VAR_EXPORT bool addressed_as_array; // whether long or string navigation used + IPAACA_MEMBER_VAR_EXPORT long addressed_index; + IPAACA_MEMBER_VAR_EXPORT std::string addressed_key; + /// currently navigated value in json tree (or a new Null value) + IPAACA_MEMBER_VAR_EXPORT rapidjson::Value* json_value; +/* protected: + IPAACA_HEADER_EXPORT void connect_to_existing_parents(); +*/ + public: + // constructor to create a new top-most parent proxy (from a payload key) + IPAACA_HEADER_EXPORT PayloadEntryProxy(Payload* payload, const std::string& key); + // constructors for navigation through objects + IPAACA_HEADER_EXPORT PayloadEntryProxy(PayloadEntryProxy* parent, const std::string& addressed_key); + IPAACA_HEADER_EXPORT PayloadEntryProxy(PayloadEntryProxy* parent, size_t addressed_index); + public: + IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](size_t index); // array-style navigation + IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const std::string& key); + IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const char* key); + // + IPAACA_HEADER_EXPORT template<typename T> PayloadEntryProxy& operator=(T t) + { + PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required + rapidjson::Value& newval = new_entry->get_or_create_nested_value_from_proxy_path(this); + pack_into_json_value(newval, new_entry->document.GetAllocator(), t); + _payload->set(_key, new_entry); + return *this; + } + + //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const std::string& value); + //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const char* value); + //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(double value); + //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(bool value); + + IPAACA_HEADER_EXPORT operator std::string(); + IPAACA_HEADER_EXPORT operator long(); + IPAACA_HEADER_EXPORT operator double(); + IPAACA_HEADER_EXPORT operator bool(); + IPAACA_HEADER_EXPORT template<typename Inner> operator std::vector<Inner>() { + if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError(); + std::vector<Inner> result; + for (auto it = json_value->Begin(); it != json_value->End(); ++it) { + result.push_back( json_value_cast<Inner>(*it) ); + } + return result; + } + IPAACA_HEADER_EXPORT template<typename Inner> operator std::list<Inner>() { + if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError(); + std::list<Inner> result; + for (auto it = json_value->Begin(); it != json_value->End(); ++it) { + result.push_back( json_value_cast<Inner>(*it) ); + } + return result; + } + IPAACA_HEADER_EXPORT template<typename Inner> operator std::map<std::string, Inner>() { + if ((!json_value) || (!json_value->IsObject())) throw PayloadAddressingError(); + std::map<std::string, Inner> result; + for (auto it = json_value->MemberBegin(); it != json_value->MemberEnd(); ++it) { + result[std::string(it->name.GetString())] = json_value_cast<Inner>(it->value); + } + return result; + } + // FIXME why are these needed again? + IPAACA_HEADER_EXPORT std::string to_str(); + //long to_int() { return operator long(); ; + IPAACA_HEADER_EXPORT long to_long(); + IPAACA_HEADER_EXPORT double to_float(); + IPAACA_HEADER_EXPORT bool to_bool(); + // getters + IPAACA_HEADER_EXPORT template<typename T> T get() { return json_value_cast<T>(json_value); } // specializations below + // setters + IPAACA_HEADER_EXPORT template<typename T> PayloadEntryProxy& set(T t); + /*{ + pack_into_json_value<T>(t); + connect_to_existing_parents(); + _payload->set(key, document_entry->document); + }*/ +}; +// Available interpretations of payload entries (or children thereof) below. +// Usage of standard complex data structures (vector etc.) currently entails +// casting all entries to a uniform type (a-priori choice: std::string). +/* +IPAACA_HEADER_EXPORT template<> long PayloadEntryProxy::get(); +IPAACA_HEADER_EXPORT template<> double PayloadEntryProxy::get(); +IPAACA_HEADER_EXPORT template<> bool PayloadEntryProxy::get(); +IPAACA_HEADER_EXPORT template<> std::string PayloadEntryProxy::get(); +IPAACA_HEADER_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get(); +IPAACA_HEADER_EXPORT template<> std::list<std::string> PayloadEntryProxy::get(); +IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get(); +*/ + +//}}} + #endif diff --git a/ipaacalib/cpp/src/ipaaca-fake.cc b/ipaacalib/cpp/src/ipaaca-fake.cc index 0cb444beeb4906f9eeec45a06775c6e24a16adc2..df0354c931ab4e5e1dff4df41c02dc828ee95452 100644 --- a/ipaacalib/cpp/src/ipaaca-fake.cc +++ b/ipaacalib/cpp/src/ipaaca-fake.cc @@ -35,11 +35,15 @@ namespace ipaaca { -IPAACA_EXPORT inline FakeIU::FakeIU() { IPAACA_INFO("") } +IPAACA_EXPORT inline FakeIU::FakeIU() { + IPAACA_INFO("") +} IPAACA_EXPORT boost::shared_ptr<FakeIU> FakeIU::create() { IPAACA_INFO(""); - return boost::shared_ptr<FakeIU>(new FakeIU()); + auto iu = boost::shared_ptr<FakeIU>(new FakeIU()); + iu->_payload.initialize(iu); + return iu; } IPAACA_EXPORT void FakeIU::add_fake_payload_item(const std::string& key, PayloadDocumentEntry::ptr entry) { diff --git a/ipaacalib/cpp/src/ipaaca-json.cc b/ipaacalib/cpp/src/ipaaca-json.cc index d5dd285cc9b9aa6839da7bff1b25907998107adf..83ac873f7de2187baa0aecbb291b369db36d8d0d 100644 --- a/ipaacalib/cpp/src/ipaaca-json.cc +++ b/ipaacalib/cpp/src/ipaaca-json.cc @@ -34,6 +34,8 @@ #include <ipaaca/ipaaca.h> #include <ipaaca/ipaaca-json.h> +#include <iomanip> + using namespace rapidjson; using namespace std; @@ -131,179 +133,25 @@ int main(int argc, char** argv) { //iu->payload()["b"] = "newEntry"; //std::vector<long> vs = { 10, 20, 30, 40 }; - std::map<std::string, double> vs = { {"A", 10}, {"B", 20}, {"C", 30}, {"D", 40} }; - ipaaca::pack_into_json_value(entry->document, entry->document.GetAllocator(), vs); - { + //std::map<std::string, double> vs = { {"A", 10}, {"B", 20}, {"C", 30}, {"D", 40} }; + //ipaaca::pack_into_json_value(entry->document, entry->document.GetAllocator(), vs); + std::cout << "Setting a value deep in the object:" << std::endl; + //iu->payload()["a"][(int)0] = "set by pep::op="; + iu->payload()["a"]["A"] = "set by pep::op="; + + std::cout << "Final payload (printed as strings):" << std::endl; + std::map<std::string, std::string> pl_flat = iu->payload(); + for (auto& kv: pl_flat) { + std::cout << " " << std::left << std::setw(15) << (kv.first+": ") << kv.second << std::endl; + } + /*{ StringBuffer buffer; Writer<StringBuffer> writer(buffer); entry->document.Accept(writer); std::string docstring = buffer.GetString(); std::cout << "Final document: " << docstring << std::endl; - } + }*/ // Done return 0; - - //////////////////////////////////////////////////////////////////////////// - // 1. Parse a JSON text string to a document. - const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4], \"dict\":{\"s\":\"stringvalue\", \"arr\":[6, 7, \"test\"]} } "; - printf("Original JSON:\n %s\n", json); - - ipaaca::PayloadDocumentStore ds; - ds["document_test"] = std::make_shared<ipaaca::PayloadDocumentEntry>(); - Document& document = ds["document_test"]->document; - - //std::map<std::string, Document> documents; - //Document _document; // Default template parameter uses UTF8 and MemoryPoolAllocator. - //documents["document_test"] = std::move(_document); - //Document& document = documents["document_test"]; - - printf("Check whether document contains 'none' initially ..."); - assert(document.IsNull()); // initial state of object -#if 1 - // "normal" parsing, decode strings to new buffers. Can use other input stream via ParseStream(). - if (document.Parse(json).HasParseError()) - return 1; -#else - // In-situ parsing, decode strings directly in the source string. Source must be string. - { - char buffer[sizeof(json)]; - memcpy(buffer, json, sizeof(json)); - if (document.ParseInsitu(buffer).HasParseError()) - return 1; - } -#endif - printf("\nParsing succeeded.\n"); - //////////////////////////////////////////////////////////////////////////// - - assert(document.IsObject()); // testing dict here - assert(document.HasMember("dict")); - assert(document["dict"].IsObject()); - assert(document["dict"].HasMember("s")); - assert(document["dict"]["s"].IsString()); - assert(document["dict"].HasMember("arr")); - assert(document["dict"]["arr"].IsArray()); - Value& arr = document["dict"]["arr"]; - printf("dict.arr size: %d\n", arr.Size()); - for (SizeType i = 0; i < arr.Size(); i++) { - if (arr[i].IsInt()) { - printf("a[%d] = %d\n", i, arr[i].GetInt()); - } else { - printf("a[%d] = \"%s\"\n", i, arr[i].GetString()); - } - } - puts("Putting new dict in array.\n"); - Document::AllocatorType& allocator = document.GetAllocator(); - Value dict; - Value insertstr; - insertstr.SetString("testvalue", allocator); - dict.SetObject(); - dict.AddMember("testkey", insertstr, allocator); - arr.PushBack(dict, allocator); - - Value newint; - newint.SetInt(12345); - document["i"] = newint; - puts("Done.\n"); - // ->Assertion failed in []: - // Value& nonexisting = document["dict"]["NONEXISTING"]; - -#if 0 - // 2. Access values in document. - printf("\nAccess values in document:\n"); - assert(document.IsObject()); // Document is a JSON value represents the root of DOM. Root can be either an object or array. - assert(document.HasMember("hello")); - assert(document["hello"].IsString()); - printf("hello = %s\n", document["hello"].GetString()); - // Since version 0.2, you can use single lookup to check the existing of member and its value: - Value::MemberIterator hello = document.FindMember("hello"); - assert(hello != document.MemberEnd()); - assert(hello->value.IsString()); - assert(strcmp("world", hello->value.GetString()) == 0); - (void)hello; - assert(document["t"].IsBool()); // JSON true/false are bool. Can also uses more specific function IsTrue(). - printf("t = %s\n", document["t"].GetBool() ? "true" : "false"); - assert(document["f"].IsBool()); - printf("f = %s\n", document["f"].GetBool() ? "true" : "false"); - printf("n = %s\n", document["n"].IsNull() ? "null" : "?"); - assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type. - assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true. - printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"] - assert(document["pi"].IsNumber()); - assert(document["pi"].IsDouble()); - printf("pi = %g\n", document["pi"].GetDouble()); - { - const Value& a = document["a"]; // Using a reference for consecutive access is handy and faster. - assert(a.IsArray()); - for (SizeType i = 0; i < a.Size(); i++) // rapidjson uses SizeType instead of size_t. - printf("a[%d] = %d\n", i, a[i].GetInt()); - int y = a[0].GetInt(); - (void)y; - // Iterating array with iterators - printf("a = "); - for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) - printf("%d ", itr->GetInt()); - printf("\n"); - } - // Iterating object members - static const char* kTypeNames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" }; - for (Value::ConstMemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr) - printf("Type of member %s is %s\n", itr->name.GetString(), kTypeNames[itr->value.GetType()]); - //////////////////////////////////////////////////////////////////////////// - // 3. Modify values in document. - // Change i to a bigger number - { - uint64_t f20 = 1; // compute factorial of 20 - for (uint64_t j = 1; j <= 20; j++) - f20 *= j; - document["i"] = f20; // Alternate form: document["i"].SetUint64(f20) - assert(!document["i"].IsInt()); // No longer can be cast as int or uint. - } - // Adding values to array. - { - Value& a = document["a"]; // This time we uses non-const reference. - Document::AllocatorType& allocator = document.GetAllocator(); - for (int i = 5; i <= 10; i++) - a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's. - // Fluent API - a.PushBack("Lua", allocator).PushBack("Mio", allocator); - } - // Making string values. - // This version of SetString() just store the pointer to the string. - // So it is for literal and string that exists within value's life-cycle. - { - document["hello"] = "rapidjson"; // This will invoke strlen() - // Faster version: - // document["hello"].SetString("rapidjson", 9); - } - // This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer. - Value author; - { - char buffer[10]; - int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string. - author.SetString(buffer, static_cast<size_t>(len), document.GetAllocator()); - // Shorter but slower version: - // document["hello"].SetString(buffer, document.GetAllocator()); - // Constructor version: - // Value author(buffer, len, document.GetAllocator()); - // Value author(buffer, document.GetAllocator()); - memset(buffer, 0, sizeof(buffer)); // For demonstration purpose. - } - // Variable 'buffer' is unusable now but 'author' has already made a copy. - document.AddMember("author", author, document.GetAllocator()); - assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null. - //////////////////////////////////////////////////////////////////////////// -#endif - StringBuffer buffer; - Writer<StringBuffer> writer(buffer); - document.Accept(writer); - std::string docstring = buffer.GetString(); - std::cout << "FIRST DUMP: " << docstring << std::endl; - - //// 4. Stringify JSON - //printf("\nModified JSON with reformatting:\n"); - //FileStream f(stdout); - //PrettyWriter<FileStream> writer(f); - //document.Accept(writer); // Accept() traverses the DOM and generates Handler events. - return 0; } diff --git a/ipaacalib/cpp/src/ipaaca-payload.cc b/ipaacalib/cpp/src/ipaaca-payload.cc index aeb95163905f0525325cc99c5d21cc5bf6d31ade..7393ab6333a9470313cdf7a6e146c12696fe2df8 100644 --- a/ipaacalib/cpp/src/ipaaca-payload.cc +++ b/ipaacalib/cpp/src/ipaaca-payload.cc @@ -142,6 +142,10 @@ IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject { valueobject.SetString(newvalue.c_str(), allocator); } +IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const char* newvalue) +{ + valueobject.SetString(newvalue, allocator); +} /* IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::vector<std::string>& newvalue) { @@ -185,16 +189,89 @@ IPAACA_EXPORT inline PayloadDocumentEntry::ptr PayloadDocumentEntry::create_null entry->json_source = "null"; // rapidjson::Document value is also null implicitly return entry; } -IPAACA_EXPORT inline PayloadDocumentEntry::ptr PayloadDocumentEntry::clone() +IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::clone() { + IPAACA_INFO("") return PayloadDocumentEntry::from_json_string_representation(this->json_source); } +IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value_from_proxy_path(PayloadEntryProxy* pep) +{ + if (!(pep->parent)) { + IPAACA_INFO("Reached top-most parent") + return document; + } + IPAACA_INFO("(Check parent)") + rapidjson::Value& parent_value = get_or_create_nested_value_from_proxy_path(pep->parent); + IPAACA_INFO("Resolving address path") + if (pep->addressed_as_array) { + IPAACA_INFO("Addressed as array with index " << pep->addressed_index) + if (! parent_value.IsArray()) { + throw PayloadAddressingError(); + } else { + long idx = pep->addressed_index; + long s = parent_value.Size(); + if (idx<s) { + return parent_value[idx]; + } else { + throw PayloadAddressingError(); + } + } + // for append / push_back? : + /*if (parent_value.IsNull()) { + wasnull = true; + parent_value.SetArray(); + } + if (wasnull || parent_value.IsArray()) { + long idx = pep->addressed_index; + long s = parent_value.Size(); + if (idx<s) { + // existing element modified + parent_value[idx] = *json_value; + } else { + // implicitly initialize missing elements to null values + if (idx>s) { + long missing_elements = pep->addressed_index - p; + for (int i=0; i<missing_elements; ++i) { + parent_value.PushBack(, allocator) + } + } + } + if (s == + } else { + throw PayloadAddressingError(); + }*/ + } else { + IPAACA_INFO("Addressed as dict with key " << pep->addressed_key) + // addressed as object (dict) + //rapidjson::Value& parent_value = *(pep->parent->json_value); + if (! parent_value.IsObject()) { + throw PayloadAddressingError(); + } else { + rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); + //Value key; + //key.SetString(pep->addressed_key, allocator); + //parent_value.AddMember(key, *json_value, allocator); + Value key; + key.SetString(pep->addressed_key, allocator); + // FIXME LAST this complains + auto it = parent_value.FindMember(key); + if (it != parent_value.MemberEnd()) { + return parent_value[pep->addressed_key.c_str()]; + } else { + rapidjson::Value val; + parent_value.AddMember(key, val, allocator); + return parent_value[key]; + } + } + } +} //}}} // PayloadEntryProxy//{{{ // only if not top-level +#if 0 IPAACA_EXPORT void PayloadEntryProxy::connect_to_existing_parents() { rapidjson::Document::AllocatorType& allocator = document_entry->document.GetAllocator(); @@ -251,55 +328,81 @@ IPAACA_EXPORT void PayloadEntryProxy::connect_to_existing_parents() pep = pep->parent; } } - +#endif IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(Payload* payload, const std::string& key) : _payload(payload), _key(key), parent(nullptr) { + IPAACA_INFO("PEP construction on parent document ...") document_entry = _payload->get_entry(key); json_value = &(document_entry->document); + IPAACA_INFO("... parent done.") } IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, const std::string& addr_key_) : parent(parent_), addressed_key(addr_key_), addressed_as_array(false) { + IPAACA_INFO("PEP construction as dict child, addressed by " << addr_key_ << " ...") _payload = parent->_payload; _key = parent->_key; document_entry = parent->document_entry; auto it = parent->json_value->FindMember(addr_key_.c_str()); - if (it != json_value->MemberEnd()) { + if (it != parent->json_value->MemberEnd()) { json_value = &(parent->json_value->operator[](addr_key_.c_str())); existent = true; } else { json_value = nullptr; // avoid heap construction here existent = false; } + IPAACA_INFO("... dict child done.") } IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, size_t addr_idx_) : parent(parent_), addressed_index(addr_idx_), addressed_as_array(true) { + IPAACA_INFO("PEP construction as array child, addressed by " << addr_idx_ << " ...") _payload = parent->_payload; _key = parent->_key; document_entry = parent->document_entry; json_value = &(parent->json_value->operator[](addr_idx_)); existent = true; + IPAACA_INFO("... array child done.") } +IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const char* addr_key_) +{ + return operator[](std::string(addr_key_)); +} IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const std::string& addr_key_) { - if (!json_value) throw PayloadAddressingError(); - if (! json_value->IsObject()) throw PayloadAddressingError(); + if (!json_value) { + IPAACA_INFO("Invalid json_value!") + throw PayloadAddressingError(); + } + if (! json_value->IsObject()) { + IPAACA_INFO("Expected Object for operator[](string)!") + throw PayloadAddressingError(); + } return PayloadEntryProxy(this, addr_key_); } IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](size_t addr_idx_) { - if (!json_value) throw PayloadAddressingError(); - if (! json_value->IsArray()) throw PayloadAddressingError(); + if (!json_value) { + IPAACA_INFO("Invalid json_value!") + throw PayloadAddressingError(); + } + if (! json_value->IsArray()) { + IPAACA_INFO("Expected Array for operator[](size_t)!") + throw PayloadAddressingError(); + } long s = json_value->Size(); - if (addr_idx_>=s) throw PayloadAddressingError(); + if (addr_idx_>=s) { + IPAACA_INFO("Array out of bounds!") + throw PayloadAddressingError(); + } return PayloadEntryProxy(this, addr_idx_); } +/* IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const std::string& value) { //std::cout << "operator=(string)" << std::endl; @@ -328,6 +431,7 @@ IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(bool value) //_payload->set(_key, boost::lexical_cast<std::string>(value)); return *this; } +*/ IPAACA_EXPORT PayloadEntryProxy::operator std::string() { @@ -443,11 +547,12 @@ IPAACA_EXPORT PayloadEntryProxy Payload::operator[](const std::string& key) //boost::shared_ptr<PayloadEntryProxy> p(new PayloadEntryProxy(this, key)); return PayloadEntryProxy(this, key); } + IPAACA_EXPORT Payload::operator std::map<std::string, std::string>() { std::map<std::string, std::string> result; std::for_each(_document_store.begin(), _document_store.end(), [&result](std::pair<std::string, PayloadDocumentEntry::ptr> pair) { - result[pair.first] = pair.second->document.GetString(); + result[pair.first] = json_value_cast<std::string>(pair.second->document); }); return result; }