diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h index a4d2f26f0a60dddbb399155989cb0bca2a9121f1..0c09880dfb743245b6f34749801c5c52fa4afe6a 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h @@ -254,10 +254,64 @@ IPAACA_HEADER_EXPORT class PayloadIterator//{{{ }; //}}} +IPAACA_HEADER_EXPORT class PayloadEntryProxyMapIterator//{{{ +{ + public: + typedef rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>::MemberIterator RawIterator; + protected: + IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy; + IPAACA_MEMBER_VAR_EXPORT RawIterator raw_iterator; + public: + IPAACA_HEADER_EXPORT PayloadEntryProxyMapIterator(PayloadEntryProxy* proxy, RawIterator&& raw_iter); + IPAACA_HEADER_EXPORT PayloadEntryProxyMapIterator& operator++(); + IPAACA_HEADER_EXPORT std::pair<std::string, PayloadEntryProxy> operator*(); + IPAACA_HEADER_EXPORT std::shared_ptr<std::pair<std::string, PayloadEntryProxy> > operator->(); + IPAACA_HEADER_EXPORT bool operator==(const PayloadEntryProxyMapIterator& other_iter); + IPAACA_HEADER_EXPORT bool operator!=(const PayloadEntryProxyMapIterator& other_iter); +}; +//}}} +IPAACA_HEADER_EXPORT class PayloadEntryProxyListIterator//{{{ +{ + protected: + IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy; + IPAACA_MEMBER_VAR_EXPORT size_t current_idx; + IPAACA_MEMBER_VAR_EXPORT size_t size; + public: + IPAACA_HEADER_EXPORT PayloadEntryProxyListIterator(PayloadEntryProxy* proxy, size_t idx, size_t size); + IPAACA_HEADER_EXPORT PayloadEntryProxyListIterator& operator++(); + IPAACA_HEADER_EXPORT PayloadEntryProxy operator*(); + IPAACA_HEADER_EXPORT std::shared_ptr<PayloadEntryProxy> operator->(); + IPAACA_HEADER_EXPORT bool operator==(const PayloadEntryProxyListIterator& other_iter); + IPAACA_HEADER_EXPORT bool operator!=(const PayloadEntryProxyListIterator& other_iter); +}; +//}}} +IPAACA_HEADER_EXPORT class PayloadEntryProxyMapDecorator//{{{ +{ + public: + IPAACA_HEADER_EXPORT inline PayloadEntryProxyMapDecorator(PayloadEntryProxy* proxy_): proxy(proxy_) { } + IPAACA_HEADER_EXPORT PayloadEntryProxyMapIterator begin(); + IPAACA_HEADER_EXPORT PayloadEntryProxyMapIterator end(); + protected: + IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy; +}; +//}}} +IPAACA_HEADER_EXPORT class PayloadEntryProxyListDecorator//{{{ +{ + public: + IPAACA_HEADER_EXPORT inline PayloadEntryProxyListDecorator(PayloadEntryProxy* proxy_): proxy(proxy_) { } + IPAACA_HEADER_EXPORT PayloadEntryProxyListIterator begin(); + IPAACA_HEADER_EXPORT PayloadEntryProxyListIterator end(); + protected: + IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy; +}; +//}}} IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ { friend std::ostream& operator<<(std::ostream& os, const PayloadEntryProxy& proxy); protected: + public: + IPAACA_HEADER_EXPORT PayloadEntryProxyMapDecorator as_map(); + IPAACA_HEADER_EXPORT PayloadEntryProxyListDecorator as_list(); public: //IPAACA_MEMBER_VAR_EXPORT rapidjson::Document* _json_parent_node; //IPAACA_MEMBER_VAR_EXPORT rapidjson::Document* _json_node; @@ -283,6 +337,8 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ // 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 size_t size(); public: IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](size_t index); // array-style navigation IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](int index); // int is UNFORTUNATELY required to catch diff --git a/ipaacalib/cpp/src/ipaaca-json.cc b/ipaacalib/cpp/src/ipaaca-json.cc index 3be11f627afce223d5134b36233329c89741f017..4124d3994f702e26c643398d522d1f8e01976de4 100644 --- a/ipaacalib/cpp/src/ipaaca-json.cc +++ b/ipaacalib/cpp/src/ipaaca-json.cc @@ -41,7 +41,20 @@ using namespace std; int iterators_main(int argc, char** argv)//{{{ { - std::string json_source("[\"old\",2,3,{\"key1\":\"value1\", \"key2\":\"value2\"}]"); + std::string json_source("[\n\ + \"old\",\n\ + [\n\ + \"str\",\n\ + null\n\ + ],\n\ + 3,\n\ + {\n\ + \"key1\": \"value1\",\n\ + \"key2\": \"value2\"\n\ + }\n\ +]"); + + std::cout << "Using this JSON document as initial payload entry 'a':" << std::endl << json_source << std::endl; ipaaca::PayloadDocumentEntry::ptr entry = ipaaca::PayloadDocumentEntry::from_json_string_representation(json_source); ipaaca::FakeIU::ptr iu = ipaaca::FakeIU::create(); @@ -50,14 +63,18 @@ int iterators_main(int argc, char** argv)//{{{ iu->payload()["bPrime"] = "simpleString"; iu->payload()["c"] = "anotherSimpleString"; iu->payload()["d"] = 100; - iu->payload()["e"] = 10000l; + iu->payload()["e"] = 3l; - std::cout << "Iterate over payload" << std::endl; + std::cout << std::endl << "Iterate over payload" << std::endl; for (auto it = iu->payload().begin(); it != iu->payload().end(); ++it) { std::cout << " " << it->first << " -> " << it->second << std::endl; } + std::cout << std::endl << "Iterate over payload, range-based" << std::endl; + for (auto it: iu->payload()) { + std::cout << " " << it.first << " -> " << it.second << std::endl; + } - std::cout << "Comparisons" << std::endl; + std::cout << std::endl << "Comparisons" << std::endl; bool eq; eq = iu->payload()["a"] == iu->payload()["b"]; std::cout << " a==b ? : " << (eq?"true":"false") << std::endl; @@ -69,7 +86,57 @@ int iterators_main(int argc, char** argv)//{{{ std::cout << " b==100 ? : " << (eq?"true":"false") << std::endl; eq = iu->payload()["d"] == 100; std::cout << " d==100 ? : " << (eq?"true":"false") << std::endl; - + eq = iu->payload()["a"][2] == iu->payload()["e"]; + std::cout << " a[2]==e ? : " << (eq?"true":"false") << std::endl; + + std::cout << std::endl << "Inner iterators, map (printing values as strings)" << std::endl; + try { + auto inner = iu->payload()["a"][3]; + std::cout << "Map iteration over payload['a'][3], which equals " << inner << std::endl; + std::cout << "Reported size is " << inner.size() << std::endl; + for (auto kv: inner.as_map()) { + std::cout << " \"" << kv.first << "\" -> \"" << kv.second << "\"" << std::endl; + } + } catch (ipaaca::Exception& ex) { + std::cout << " Unexpected exception: " << ex.what() << std::endl; + } + try { + auto inner = iu->payload()["a"][2]; + std::cout << "Map iteration over payload['a'][2], which equals " << inner << std::endl; + std::cout << "Reported size is " << inner.size() << std::endl; + for (auto kv: inner.as_map()) { + std::cout << " \"" << kv.first << "\" -> \"" << kv.second << "\"" << std::endl; + } + } catch (ipaaca::PayloadTypeConversionError& ex) { + std::cout << " Failed as expected with " << ex.what() << std::endl; + } catch (ipaaca::Exception& ex) { + std::cout << " Unexpected exception: " << ex.what() << std::endl; + } + + std::cout << std::endl << "Inner iterators, list (printing values as strings)" << std::endl; + try { + auto inner = iu->payload()["a"][1]; + std::cout << "List iteration over payload['a'][1], which equals " << inner << std::endl; + std::cout << "Reported size is " << inner.size() << std::endl; + for (auto proxy: inner.as_list()) { + std::cout << " \"" << proxy << "\"" << std::endl; + } + } catch (ipaaca::Exception& ex) { + std::cout << " Unexpected exception: " << ex.what() << std::endl; + } + try { + auto inner = iu->payload()["a"][1][1]; + std::cout << "List iteration over payload['a'][1][1], which equals " << inner << std::endl; + std::cout << "Reported size is " << inner.size() << std::endl; + for (auto proxy: inner.as_list()) { + std::cout << " \"" << proxy << "\"" << std::endl; + } + } catch (ipaaca::PayloadTypeConversionError& ex) { + std::cout << " Failed as expected with " << ex.what() << std::endl; + } catch (ipaaca::Exception& ex) { + std::cout << " Unexpected exception: " << ex.what() << std::endl; + } + return 0; } //}}} diff --git a/ipaacalib/cpp/src/ipaaca-payload.cc b/ipaacalib/cpp/src/ipaaca-payload.cc index e8c6d145324449e62a21c5219c1ce203ef58bab7..99117e08cb87f44466e7bf69f708582c1b3aeb37 100644 --- a/ipaacalib/cpp/src/ipaaca-payload.cc +++ b/ipaacalib/cpp/src/ipaaca-payload.cc @@ -567,6 +567,25 @@ IPAACA_EXPORT bool PayloadEntryProxy::to_bool() //return PayloadEntryProxy::get<bool>(); } +IPAACA_EXPORT PayloadEntryProxyMapDecorator PayloadEntryProxy::as_map() +{ + if (json_value && json_value->IsObject()) return PayloadEntryProxyMapDecorator(this); + throw PayloadTypeConversionError(); +} + +IPAACA_EXPORT PayloadEntryProxyListDecorator PayloadEntryProxy::as_list() +{ + if (json_value && json_value->IsArray()) return PayloadEntryProxyListDecorator(this); + throw PayloadTypeConversionError(); +} + +IPAACA_EXPORT size_t PayloadEntryProxy::size() +{ + if (!json_value) return 0; + if (json_value->IsArray()) return json_value->Size(); + if (json_value->IsObject()) return json_value->MemberCount(); + return 0; +} // // new stuff for protocol v2 @@ -772,4 +791,90 @@ IPAACA_EXPORT bool PayloadIterator::operator!=(const PayloadIterator& ref) } //}}} +// PayloadEntryProxyMapIterator//{{{ +IPAACA_EXPORT PayloadEntryProxyMapIterator::PayloadEntryProxyMapIterator(PayloadEntryProxy* proxy_, RawIterator&& raw_iter) +: proxy(proxy_), raw_iterator(std::move(raw_iter)) +{ +} + +IPAACA_EXPORT PayloadEntryProxyMapIterator& PayloadEntryProxyMapIterator::operator++() +{ + // prevent increase beyond end() ? + raw_iterator++; + return *this; +} + +IPAACA_EXPORT std::pair<std::string, PayloadEntryProxy> PayloadEntryProxyMapIterator::operator*() +{ + std::string key = raw_iterator->name.GetString(); + return std::pair<std::string, PayloadEntryProxy>(key, (*proxy)[key] ); // generates child Proxy +} + +IPAACA_EXPORT std::shared_ptr<std::pair<std::string, PayloadEntryProxy> > PayloadEntryProxyMapIterator::operator->() +{ + std::string key = raw_iterator->name.GetString(); + return std::make_shared<std::pair<std::string, PayloadEntryProxy> >(key, (*proxy)[key] ); // generates child Proxy +} +IPAACA_EXPORT bool PayloadEntryProxyMapIterator::operator==(const PayloadEntryProxyMapIterator& other_iter) +{ + return raw_iterator==other_iter.raw_iterator; +} +IPAACA_EXPORT bool PayloadEntryProxyMapIterator::operator!=(const PayloadEntryProxyMapIterator& other_iter) +{ + return raw_iterator!=other_iter.raw_iterator; +} +//}}} +// PayloadEntryProxyMapDecorator//{{{ +PayloadEntryProxyMapIterator PayloadEntryProxyMapDecorator::begin() +{ + return PayloadEntryProxyMapIterator(proxy, proxy->json_value->MemberBegin()); +} +PayloadEntryProxyMapIterator PayloadEntryProxyMapDecorator::end() +{ + return PayloadEntryProxyMapIterator(proxy, proxy->json_value->MemberEnd()); +} +//}}} + +// PayloadEntryProxyListIterator//{{{ +IPAACA_EXPORT PayloadEntryProxyListIterator::PayloadEntryProxyListIterator(PayloadEntryProxy* proxy_, size_t idx, size_t size_) +: proxy(proxy_), current_idx(idx), size(size_) +{ +} + +IPAACA_EXPORT PayloadEntryProxyListIterator& PayloadEntryProxyListIterator::operator++() +{ + if (current_idx!=size) current_idx++; + return *this; +} + +IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxyListIterator::operator*() +{ + return (*proxy)[current_idx]; +} + +IPAACA_EXPORT std::shared_ptr<PayloadEntryProxy> PayloadEntryProxyListIterator::operator->() +{ + return std::make_shared<PayloadEntryProxy>((*proxy)[current_idx]); +} +IPAACA_EXPORT bool PayloadEntryProxyListIterator::operator==(const PayloadEntryProxyListIterator& other_iter) +{ + return (proxy==other_iter.proxy) && (current_idx==other_iter.current_idx); +} +IPAACA_EXPORT bool PayloadEntryProxyListIterator::operator!=(const PayloadEntryProxyListIterator& other_iter) +{ + return (current_idx!=other_iter.current_idx) || (proxy!=other_iter.proxy); +} +//}}} +// PayloadEntryProxyListDecorator//{{{ +PayloadEntryProxyListIterator PayloadEntryProxyListDecorator::begin() +{ + return PayloadEntryProxyListIterator(proxy, 0, proxy->json_value->Size()); +} +PayloadEntryProxyListIterator PayloadEntryProxyListDecorator::end() +{ + size_t size = proxy->json_value->Size(); + return PayloadEntryProxyListIterator(proxy, size, size); +} +//}}} + } // of namespace ipaaca