From 9f384144ed2c421fff2c698e68710557dda6be1f Mon Sep 17 00:00:00 2001 From: Ramin Yaghoubzadeh <ryaghoubzadeh@uni-bielefeld.de> Date: Fri, 27 Mar 2015 18:42:54 +0100 Subject: [PATCH] C++: Initial basic documentation of all relevant classes. Also changed constructors of PayloadEntryProxy to protected. --- ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h | 71 +++++++- ipaacalib/cpp/include/ipaaca/ipaaca-ius.h | 53 ++++++ ipaacalib/cpp/include/ipaaca/ipaaca-payload.h | 158 +++++++++++------- ipaacalib/cpp/include/ipaaca/ipaaca.h | 3 +- ipaacalib/cpp/src/ipaaca-buffers.cc | 11 ++ 5 files changed, 228 insertions(+), 68 deletions(-) diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h b/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h index 806ff3c..2b57075 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h @@ -69,6 +69,7 @@ IPAACA_HEADER_EXPORT class SmartLinkMap {//{{{ IPAACA_HEADER_EXPORT void _replace_links(const LinkMap& links); };//}}} +/// The empty link set is returned if undefined links are read for an IU. IPAACA_MEMBER_VAR_EXPORT const LinkSet EMPTY_LINK_SET; /// Configuration object that can be passed to Buffer constructors. @@ -113,11 +114,20 @@ IPAACA_HEADER_EXPORT class BufferConfigurationBuilder: private BufferConfigurati };//}}} -/// Type of user-space functions that can be registered on a Buffer to receive IU events. +/** \brief Type of user-space functions that can be registered on a Buffer to receive IU events. + * + * The signature of these functions is void(shared_ptr<IUInterface> iu, IUEventType evt_type, bool local), where:<br/> + * iu can be used mostly like a locally-generated IU reference (e.g. iu->payload() ...)<br/> + * evt_type is one of IU_ADDED, IU_UPDATED, IU_RETRACTED, IU_DELETED, IU_LINKSUPDATED, IU_COMMITTED, IU_MESSAGE<br/> + * local indicates that a remote change to a local IU (in an OutputBuffer) was effected + * + * + */ IPAACA_HEADER_EXPORT typedef boost::function<void (boost::shared_ptr<IUInterface>, IUEventType, bool)> IUEventHandlerFunction; -/// Internal handler type (wraps used-specified IUEventHandlerFunction) -IPAACA_LOG_LEVEL_NONE, IPAACA_HEADER_EXPORT class IUEventHandler {//{{{ +/** \brief Internal handler type used in Buffer (wraps used-specified IUEventHandlerFunction) + */ +IPAACA_HEADER_EXPORT class IUEventHandler {//{{{ protected: IPAACA_MEMBER_VAR_EXPORT IUEventHandlerFunction _function; IPAACA_MEMBER_VAR_EXPORT IUEventType _event_mask; @@ -137,9 +147,9 @@ IPAACA_LOG_LEVEL_NONE, IPAACA_HEADER_EXPORT class IUEventHandler {//{{{ };//}}} /** - * \brief Buffer base class + * \brief Buffer base class. Derived classes use its handler registration functionality. * - * This class is never instantiated directly (use OutputBuffer and InputBuffer, respectively). + * \b Note: This class is never instantiated directly (use OutputBuffer and InputBuffer, respectively). */ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Buffer> {//{{{ friend class IU; @@ -173,7 +183,42 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu public: IPAACA_HEADER_EXPORT virtual inline ~Buffer() { } IPAACA_HEADER_EXPORT inline const std::string& unique_name() { return _unique_name; } + /// This version of register_handler takes a set of several category interests instead of just one. IPAACA_HEADER_EXPORT void register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories); + /** \brief Register a user-specified handler for IU events. + * + * \param function A function [object] that can be converted to #IUEventHandlerFunction (examples below) + * \param event_mask Which event types to relay to the user (default: all) + * \param category The category to filter for (default: do not filter) + * + * \b Examples: + * + * Adding a plain function as a handler:<br/> + * <pre> + * void global_iu_handler(IUInterface::ptr iu, IUEventType type, bool local) { ... } + * ... + * int main() { + * OutputBuffer::ptr outbuf = OutputBuffer::create("mybufname"); + * outbuf->register_handler(global_iu_handler); + * ... + * } + * </pre> + * + * Adding a class member as a handler (using boost::bind):<br/> + * <pre> + * class MyClass { + * protected: + * void my_internal_iu_handler(IUInterface::ptr iu, IUEventType type, bool local) { ... } + * InputBuffer::ptr inbuf; + * public: + * MyClass() { + * inbuf = InputBuffer::create("bufname", "categoryInterest"); + * inbuf->register_handler(boost::bind(&MyClass::my_internal_iu_handler, this, _1, _2, _3)); + * } + * }; + * </pre> + * + */ IPAACA_HEADER_EXPORT void register_handler(IUEventHandlerFunction function, IUEventType event_mask = IU_ALL_EVENTS, const std::string& category=""); //_IPAACA_ABSTRACT_ virtual void add(boost::shared_ptr<IUInterface> iu) = 0; IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual boost::shared_ptr<IUInterface> get(const std::string& iu_uid) = 0; @@ -225,6 +270,7 @@ IPAACA_HEADER_EXPORT class OutputBuffer: public Buffer { //, public boost::enabl IPAACA_HEADER_EXPORT void _retract_iu(boost::shared_ptr<IU> iu); protected: + /// \b Note: constructor is protected. Use create() IPAACA_HEADER_EXPORT OutputBuffer(const std::string& basename, const std::string& channel=""); // empty string auto-replaced with __ipaaca_static_option_default_channel IPAACA_HEADER_EXPORT void _initialize_server(); public: @@ -287,6 +333,7 @@ IPAACA_HEADER_EXPORT class InputBuffer: public Buffer { //, public boost::enable IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_resendrequest() should never be invoked") }*/ protected: + /// \b Note: all constructors are protected. Use create() IPAACA_HEADER_EXPORT InputBuffer(const BufferConfiguration& bufferconfiguration); IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::set<std::string>& category_interests); IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::vector<std::string>& category_interests); @@ -298,15 +345,27 @@ IPAACA_HEADER_EXPORT class InputBuffer: public Buffer { //, public boost::enable IPAACA_MEMBER_VAR_EXPORT bool triggerResend; public: - /// Specify whether old, but previously unknown, IUs should be requested to be sent to the buffer over a hidden channel. + /// Specify whether old but previously unseen IUs should be requested to be sent to the buffer over a hidden channel. IPAACA_HEADER_EXPORT void set_resend(bool resendActive); IPAACA_HEADER_EXPORT bool get_resend(); + /// Create InputBuffer according to configuration in BufferConfiguration object IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const BufferConfiguration& bufferconfiguration); + /// Create InputBuffer from name and set of category interests IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::set<std::string>& category_interests); + /// Create InputBuffer from name and vector of category interests IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::vector<std::string>& category_interests); + // /// Create InputBuffer from name and initializer_list of category interests + // IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::initializer_list<std::string>& category_interests); + /// Convenience function: create InputBuffer from name and one category interest IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1); + /// Convenience function: create InputBuffer from name and two category interests [DEPRECATED] + [[deprecated("Use create(string, set<string>) instead")]] IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2); + /// Convenience function: create InputBuffer from name and three category interests [DEPRECATED] + [[deprecated("Use create(string, set<string>) instead")]] IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3); + /// Convenience function: create InputBuffer from name and four category interests [DEPRECATED] + [[deprecated("Use create(string, set<string>) instead")]] IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3, const std::string& category_interest4); IPAACA_HEADER_EXPORT ~InputBuffer() { IPAACA_IMPLEMENT_ME diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h b/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h index 73d9648..f4fc8fc 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h @@ -50,6 +50,14 @@ #endif +/** \brief Abstract base class for all IU-type classes + * + * In user programs, classes IU or Message should be instantiated. + * + * This abstract type is used in handler callback functions and + * contains most generic user-space functions. + * + */ IPAACA_HEADER_EXPORT class IUInterface {//{{{ friend class IUConverter; friend class MessageConverter; @@ -87,38 +95,68 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{ IPAACA_HEADER_EXPORT void _add_and_remove_links(const LinkMap& add, const LinkMap& remove) { _links._add_and_remove_links(add, remove); } IPAACA_HEADER_EXPORT void _replace_links(const LinkMap& links) { _links._replace_links(links); } public: + /// Return whether IU has already been published (is in a Buffer). IPAACA_HEADER_EXPORT inline bool is_published() { return (_buffer != 0); } + /// Return auto-generated UID string (set during IU construction) IPAACA_HEADER_EXPORT inline const std::string& uid() const { return _uid; } + /// Return current IU revision number (incremented for each update) IPAACA_HEADER_EXPORT inline revision_t revision() const { return _revision; } + /// Return the IU category string (set during IU construction) IPAACA_HEADER_EXPORT inline const std::string& category() const { return _category; } + /// Return the channel name the IU is resident on (set on publication) IPAACA_HEADER_EXPORT const std::string& channel(); + /// Return the payload type (default "JSON") IPAACA_HEADER_EXPORT inline const std::string& payload_type() const { return _payload_type; } + /// Return the owner name (unique fully-qualified buffer name, set on publication) IPAACA_HEADER_EXPORT inline const std::string& owner_name() const { return _owner_name; } + /// Return whether IU has been committed to (i.e. is complete, confirmed, and henceforth constant) IPAACA_HEADER_EXPORT inline bool committed() const { return _committed; } + /// Return the access mode (not relevant for the time being) IPAACA_HEADER_EXPORT inline IUAccessMode access_mode() const { return _access_mode; } + /// Return whether IU is read only (committed, a Message, or explicitly set read-only by owner) IPAACA_HEADER_EXPORT inline bool read_only() const { return _read_only; } //inline boost::shared_ptr<Buffer> buffer() { return _buffer; } + /// Return owning buffer [CAVEAT: do not rely on this function for future code] IPAACA_HEADER_EXPORT inline Buffer* buffer() const { return _buffer; } + /// Return the link set for an arbitrary link type (e.g. "grounded_in"), or EMPTY_LINK_SET IPAACA_HEADER_EXPORT inline const LinkSet& get_links(std::string type) { return _links.get_links(type); } + /// Return the map of all defined links IPAACA_HEADER_EXPORT inline const LinkMap& get_all_links() { return _links.get_all_links(); } // Payload + /// Return the Payload object of this IU, overridden in the derived classes IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual Payload& payload() = 0; + /// Const version of payload() IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual const Payload& const_payload() const = 0; // setters + /// Commit to an IU (only possible for the IU owner) IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void commit() = 0; // functions to modify and update links: //IPAACA_HEADER_EXPORT void _publish_resend(boost::shared_ptr<IU> iu, const std::string& hidden_scope_name); + /// Add a set of new UIDs for a specific link type IPAACA_HEADER_EXPORT void add_links(const std::string& type, const LinkSet& targets, const std::string& writer_name = ""); + /// Remove a set of UIDs from a link type IPAACA_HEADER_EXPORT void remove_links(const std::string& type, const LinkSet& targets, const std::string& writer_name = ""); + /// Bulk link modification function IPAACA_HEADER_EXPORT void modify_links(const LinkMap& add, const LinkMap& remove, const std::string& writer_name = ""); + /// Bulk link override function IPAACA_HEADER_EXPORT void set_links(const LinkMap& links, const std::string& writer_name = ""); // (with cpp specific convenience functions:) + /// Convenience function (C++): add a single UID string to an arbitrary link set IPAACA_HEADER_EXPORT void add_link(const std::string& type, const std::string& target, const std::string& writer_name = ""); + /// Convenience function (C++): remove a single UID string from an arbitrary link set (if contained) IPAACA_HEADER_EXPORT void remove_link(const std::string& type, const std::string& target, const std::string& writer_name = ""); typedef boost::shared_ptr<IUInterface> ptr; };//}}} +/** \brief Class of locally-owned IU objects. + * + * Use IU::create() (static) to create references to new IUs. + * Use IU::payload() to access the IUs payload object. + * Use OutputBuffer::add() to publish IUs. + * + * See IUInterface for a generic description of most user-space member functions. + */ IPAACA_HEADER_EXPORT class IU: public IUInterface {//{{{ friend class Buffer; friend class InputBuffer; @@ -155,6 +193,18 @@ IPAACA_HEADER_EXPORT class IU: public IUInterface {//{{{ public: typedef boost::shared_ptr<IU> ptr; };//}}} +/** \brief Class of locally-owned message objects ('one-shot' IUs). + * + * This class works the same as IU, except that it sets the internal + * flags so that it is received as a message (ephemeral object) on + * the remote sides, instead of a persistent objects. + * + * Likewise, it is not actually stored by OutputBuffer::add(), but just broadcast. + * + * See IUInterface for a generic description of most user-space member functions. + * + * \see IU, IUInterface + */ IPAACA_HEADER_EXPORT class Message: public IU {//{{{ friend class Buffer; friend class InputBuffer; @@ -181,6 +231,7 @@ IPAACA_HEADER_EXPORT class Message: public IU {//{{{ typedef boost::shared_ptr<Message> ptr; };//}}} +/// Copy of a remote IU, received in an InputBuffer. Setter functions call RPC over the backend (RSB). \b Note: Typically handled only as reference in a handler in user space. IPAACA_HEADER_EXPORT class RemotePushIU: public IUInterface {//{{{ friend class Buffer; friend class InputBuffer; @@ -209,6 +260,7 @@ IPAACA_HEADER_EXPORT class RemotePushIU: public IUInterface {//{{{ IPAACA_HEADER_EXPORT void _apply_retraction(); typedef boost::shared_ptr<RemotePushIU> ptr; };//}}} +/// Copy of a remote Message, received in an InputBuffer. Setter functions all fail.\b Note: Typically handled only as reference in a handler in user space. IPAACA_HEADER_EXPORT class RemoteMessage: public IUInterface {//{{{ friend class Buffer; friend class InputBuffer; @@ -238,6 +290,7 @@ IPAACA_HEADER_EXPORT class RemoteMessage: public IUInterface {//{{{ typedef boost::shared_ptr<RemoteMessage> ptr; };//}}} +/// Mock IU for testing purposes. [INTERNAL] IPAACA_HEADER_EXPORT class FakeIU: public IUInterface {//{{{ friend class Buffer; friend class InputBuffer; diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h index 482d137..6d8e863 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h @@ -52,6 +52,7 @@ #endif // casting operators from Value& +/// 'Smart' type conversions, allowing for some leeway type-wise (e.g. string "1.3" can be successfully cast to double or long). Used by PayloadEntryProxy. IPAACA_HEADER_EXPORT template<typename T> T json_value_cast(const rapidjson::Value&); IPAACA_HEADER_EXPORT template<typename T> T json_value_cast(const rapidjson::Value* value) { if (!value) return T(); return json_value_cast<T>(*value); } IPAACA_HEADER_EXPORT template<> long json_value_cast(const rapidjson::Value&); @@ -65,14 +66,20 @@ IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> json_value_ca // helpers to set Value& from various standard types //IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, T t); +/// Setter to store int into json value, used by PayloadEntryProxy. IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, int); +/// Setter to store int into json value, used by PayloadEntryProxy. IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, long); +/// Setter to store long into json value, used by PayloadEntryProxy. IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, double); +/// Setter to store double into json value, used by PayloadEntryProxy. IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, bool); +/// Setter to store bool into json value, used by PayloadEntryProxy. IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::string&); +/// Setter to store std::string into json value, used by PayloadEntryProxy. IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const char*); // helpers to set Value& from several standard containers containing the above standard types -/// set Value& from vector<T> +/// Setter to store a vector of supported basic types into json value, used by PayloadEntryProxy. IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::vector<T>& ts) { valueobject.SetArray(); @@ -82,7 +89,7 @@ IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::V valueobject.PushBack(newv, allocator); } } -/// set Value& from list<T> +/// Setter to store a list of supported basic types into json value, used by PayloadEntryProxy. IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::list<T>& ts) { valueobject.SetArray(); @@ -92,7 +99,7 @@ IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::V valueobject.PushBack(newv, allocator); } } -/// set Value& from map<string, T> +/// Setter to store a map of string -> supported basic types into json value, used by PayloadEntryProxy. IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::map<std::string, T>& ts) { valueobject.SetObject(); @@ -110,6 +117,8 @@ IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rap */ // FIXME TODO locking / invalidating proxy on first write of a payload entry + +/// Single payload entry wrapping a rapidjson::Document with some conversion glue. Also handles copy-on-write Document cloning. IPAACA_HEADER_EXPORT class PayloadDocumentEntry//{{{ { friend std::ostream& operator<<(std::ostream& os, std::shared_ptr<PayloadDocumentEntry> entry); @@ -132,57 +141,12 @@ IPAACA_HEADER_EXPORT class PayloadDocumentEntry//{{{ }; //}}} -/* -IPAACA_HEADER_EXPORT class LegacyStringPayloadEntryProxy//{{{ -{ - protected: - IPAACA_MEMBER_VAR_EXPORT Payload* _payload; - IPAACA_MEMBER_VAR_EXPORT std::string _key; - public: - IPAACA_HEADER_EXPORT PayloadEntryProxy(Payload* payload, 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 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(); // specializations below - // setters -}; -// 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(); - -//}}} -*/ - typedef std::map<std::string, PayloadDocumentEntry::ptr> PayloadDocumentStore; -/* -IPAACA_HEADER_EXPORT class PayloadDocumentStore//{{{ -: public std::map<std::string, PayloadDocumentEntry::ptr> -{ - public: - typedef std::shared_ptr<PayloadDocumentStore> ptr; -}; -//}}} -*/ - +/** \brief Central class containing the user-set payload of any IUInterface class (IU, Message, RemotePushIU or RemoteMessage) + * + * Obtained by calling payload() on any IUInterface derived object. Created during IU creation. + */ IPAACA_HEADER_EXPORT class Payload//{{{ { friend std::ostream& operator<<(std::ostream& os, const Payload& obj); @@ -217,20 +181,26 @@ IPAACA_HEADER_EXPORT class Payload//{{{ public: IPAACA_HEADER_EXPORT inline const std::string& owner_name() { return _owner_name; } // access + /// Obtain a payload item by name as a PayloadEntryProxy (returning null-type proxy if undefined) IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const std::string& key); + /// Legacy / convenience function: interpret the payload map as a map string->string (casting all entries to string) IPAACA_HEADER_EXPORT operator std::map<std::string, std::string>(); + /// set or overwrite a single payload entry with a PayloadDocumentEntry object (typically \b not called by users - use PayloadEntryProxy::operator=() instead). IPAACA_HEADER_EXPORT inline void set(const std::string& k, PayloadDocumentEntry::ptr entry) { _internal_set(k, entry); } + /// remove a single payload entry IPAACA_HEADER_EXPORT inline void remove(const std::string& k) { _internal_remove(k); } // FIXME: json: these two must support a bunch of standard types, not [only] json (users touch them) // to be more precise: types of map<string, T> with T several interesting things (string, list<string>, etc.) //IPAACA_HEADER_EXPORT inline void set(const std::map<std::string, const rapidjson::Document&>& all_elems) { _internal_replace_all(all_elems); } //IPAACA_HEADER_EXPORT inline void merge(const std::map<std::string, const rapidjson::Document&>& elems_to_merge) { _internal_merge(elems_to_merge); } // legacy / convenience setter + /// Legacy / convenience function: set the whole payload map from a map string->string (all JSON types are also set as string, no interpretation) IPAACA_HEADER_EXPORT void set(const std::map<std::string, std::string>& all_elems); protected: IPAACA_HEADER_EXPORT PayloadDocumentEntry::ptr get_entry(const std::string& k); // json, changed str to proxy here, too public: [[deprecated("Use operator[] and operator std::string() instead")]] + /// Read a single entry as string [DEPRECATED] (use string conversion in PayloadEntryProxy instead) IPAACA_HEADER_EXPORT std::string get(const std::string& k); // DEPRECATED protected: IPAACA_MEMBER_VAR_EXPORT unsigned long internal_revision; @@ -238,11 +208,24 @@ IPAACA_HEADER_EXPORT class Payload//{{{ public: IPAACA_HEADER_EXPORT inline bool revision_changed(unsigned long reference_revision) { return internal_revision != reference_revision; } public: + /// obtain a standard iterator marking the first entry in the payload IPAACA_HEADER_EXPORT PayloadIterator begin(); + /// obtain a standard iterator past the last entry in the payload IPAACA_HEADER_EXPORT PayloadIterator end(); typedef boost::shared_ptr<Payload> ptr; };//}}} +/** \brief Standard iterator for Payload (example below) + * + * \b Examples: + * <pre> + * // Print all key-value pairs from a payload (C++11) + * for (auto kv_pair: myiu->payload()) { + * std::cout << kv_pair.first << " -> " << (std::string) kv_pair.second << std::endl; + * } + * </pre> + * + */ IPAACA_HEADER_EXPORT class PayloadIterator//{{{ { friend class Payload; @@ -265,6 +248,7 @@ IPAACA_HEADER_EXPORT class PayloadIterator//{{{ }; //}}} +/// Iterator over a payload entry that is a json map-type object (returned type during dereferencing: pair<string, PayloadEntryProxy>) IPAACA_HEADER_EXPORT class PayloadEntryProxyMapIterator//{{{ { public: @@ -281,6 +265,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyMapIterator//{{{ IPAACA_HEADER_EXPORT bool operator!=(const PayloadEntryProxyMapIterator& other_iter); }; //}}} +/// Iterator over a payload entry that is a json list-type object (returned type during dereferencing: PayloadEntryProxy) IPAACA_HEADER_EXPORT class PayloadEntryProxyListIterator//{{{ { protected: @@ -296,6 +281,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyListIterator//{{{ IPAACA_HEADER_EXPORT bool operator!=(const PayloadEntryProxyListIterator& other_iter); }; //}}} +/// Interpretation of a variant json value as a map-type object IPAACA_HEADER_EXPORT class PayloadEntryProxyMapDecorator//{{{ { public: @@ -306,6 +292,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyMapDecorator//{{{ IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy; }; //}}} +/// Interpretation of a variant json value as a list-type object IPAACA_HEADER_EXPORT class PayloadEntryProxyListDecorator//{{{ { public: @@ -317,13 +304,37 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyListDecorator//{{{ }; //}}} -/** PayloadEntryProxy description */ +/** \brief Reference to an existent or nonexistent payload entry (or a value deeper in the json tree) + * + * This class is returned by IUInterface::operator[]. + * The proxy handles automatic type conversions, requests remote changes of payloads, and enables navigation into and iteration over structured json objects. + * + * \b Examples: + * + * <code>std::string received_name = iu->payload()["name"];</code> // implicit conversion using operator string() + * + * <code>std::vector<double> vd = iu->payload()["double_list"];</code> // some standard container types also supported + * + * <code>auto p = iu->payload()["otherKey"];</code> // auto type is PayloadEntryProxy (conversion is on-demand) + * + * <code>iu->payload()["double_list"][0] = 100.0;</code> // accessing and updating an item in a list + * + * <code>iu->payload()["name_list"] = std::list<std::string>{"Alpha", "Bravo", "Charlie"};</code> // set from basic uniform containers + * + * <code>for (auto val: iu->payload()["my_list"].as_list()) { ... }</code> // as_list is required to select list-type iteration (value type in iteration remains variant) + * + * <code>for (auto k_v_map: iu->payload()["my_map"].as_map()) { ... }</code> // as_map is required to select map-type iteration (value type in iteration is a pair, second part remains variant) + */ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ { + friend class Payload; + friend class PayloadIterator; friend std::ostream& operator<<(std::ostream& os, const PayloadEntryProxy& proxy); protected: public: + /// Select map-style iteration for this proxy (to select iterator content type). Will throw if not actually map-type. See example in the class description. IPAACA_HEADER_EXPORT PayloadEntryProxyMapDecorator as_map(); + /// Select list-style iteration for this proxy (to select iterator content type). Will throw if not actually list-type. See example in the class description. IPAACA_HEADER_EXPORT PayloadEntryProxyListDecorator as_list(); public: //IPAACA_MEMBER_VAR_EXPORT rapidjson::Document* _json_parent_node; @@ -333,41 +344,52 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ // // new json stuff / hierarchical navigation // - IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* parent; // parent (up to document root -> then null) + IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* parent; ///< Parent proxy (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; + IPAACA_MEMBER_VAR_EXPORT bool existent; ///< Whether Value exists already (or else 'blindly' navigated) + IPAACA_MEMBER_VAR_EXPORT bool addressed_as_array; ///< Whether long or string navigation was used + IPAACA_MEMBER_VAR_EXPORT long addressed_index; ///< Index that was used in list-style access + IPAACA_MEMBER_VAR_EXPORT std::string addressed_key; ///< Key that was used in map-style access /// currently navigated value in json tree (or a new Null value) - IPAACA_MEMBER_VAR_EXPORT rapidjson::Value* json_value; + IPAACA_MEMBER_VAR_EXPORT rapidjson::Value* json_value; ///< json value that corresponds to the current navigation (or nullptr) /* protected: IPAACA_HEADER_EXPORT void connect_to_existing_parents(); */ - public: + protected: // 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: + /// Return number of contained items (or 0 for non-container types) IPAACA_HEADER_EXPORT size_t size(); + /// Return whether value corresponds to json 'null'; also true if value is nonexistent so far (e.g. navigated to new map entry) IPAACA_HEADER_EXPORT bool is_null(); + /// Return whether value is of string type IPAACA_HEADER_EXPORT bool is_string(); + /// Return whether value is of a numerical type IPAACA_HEADER_EXPORT bool is_number(); + /// Return whether value is of list type IPAACA_HEADER_EXPORT bool is_list(); + /// Return whether value is of map type IPAACA_HEADER_EXPORT bool is_map(); public: + /// Array-style navigation over json value IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](size_t index); // array-style navigation + /// Array-style navigation over json value (added to catch [0]) IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](int index); // int is UNFORTUNATELY required to catch // [0] (addressing using literal zero) // because ambiguity with const char* // arises if only [](size_t) is provided. // size_t is obviously superior ... // TODO: remove if better solution known + /// Dict-style navigation over json value IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const std::string& key); // dict-style navigation + /// Dict-style navigation over json value IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const char* key); - // + // + /// Set or overwrite some portion of a payload from the point navigated to IPAACA_HEADER_EXPORT template<typename T> PayloadEntryProxy& operator=(T t) { PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required @@ -377,8 +399,11 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ _payload->set(_key, new_entry); return *this; } + /// Value comparison with other proxy contents IPAACA_HEADER_EXPORT inline bool operator==(const PayloadEntryProxy& otherproxy) { return (json_value && otherproxy.json_value && ((*json_value)==*(otherproxy.json_value))); } + /// Value comparison with other proxy contents IPAACA_HEADER_EXPORT inline bool operator!=(const PayloadEntryProxy& otherproxy) { return !operator==(otherproxy); } + /// Value comparison with supported basic types IPAACA_HEADER_EXPORT template<typename T> bool operator==(T othervalue) { if (!json_value) return false; @@ -389,14 +414,18 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ return false; } } + /// Value comparison with supported basic types IPAACA_HEADER_EXPORT template<typename T> bool operator!=(T othervalue) { return !operator==(othervalue); } + /// Value comparison with char* (required to be explicitly added) IPAACA_HEADER_EXPORT inline bool operator==(const char* othervalue) { if (!json_value) return false; return json_value_cast<std::string>(*json_value) == othervalue; } + /// Value comparison with char* (required to be explicitly added) IPAACA_HEADER_EXPORT inline bool operator!=(const char* othervalue) { return !operator==(othervalue); } + /// Copy value from below other json node, preserving types IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const PayloadEntryProxy& otherproxy); //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const std::string& value); @@ -404,10 +433,15 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(double value); //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(bool value); + /// Conversion to std::string (explicit or implicit) IPAACA_HEADER_EXPORT operator std::string(); + /// Conversion to long (explicit or implicit) IPAACA_HEADER_EXPORT operator long(); + /// Conversion to double (explicit or implicit) IPAACA_HEADER_EXPORT operator double(); + /// Conversion to bool (explicit or implicit) IPAACA_HEADER_EXPORT operator bool(); + /// Conversion to uniform std::vector of supported basic type IPAACA_HEADER_EXPORT template<typename Inner> operator std::vector<Inner>() { if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError(); std::vector<Inner> result; @@ -416,6 +450,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ } return result; } + /// Conversion to uniform std::list of supported basic type IPAACA_HEADER_EXPORT template<typename Inner> operator std::list<Inner>() { if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError(); std::list<Inner> result; @@ -424,6 +459,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ } return result; } + /// Conversion to uniform std::map of string -> supported basic type 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; diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca.h b/ipaacalib/cpp/include/ipaaca/ipaaca.h index 7d6f242..04f62ee 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca.h @@ -51,7 +51,7 @@ List of most relevant entry points: Buffers: InputBuffer, OutputBuffer -IUs: IU, Message +IUs: IUInterface, IU, Message IU handling (user-set): #IUEventHandlerFunction @@ -190,6 +190,7 @@ IU payload contents: Payload, PayloadEntryProxy #include <list> #include <algorithm> #include <utility> +#include <initializer_list> namespace ipaaca { diff --git a/ipaacalib/cpp/src/ipaaca-buffers.cc b/ipaacalib/cpp/src/ipaaca-buffers.cc index 99a2b91..6ef4496 100644 --- a/ipaacalib/cpp/src/ipaaca-buffers.cc +++ b/ipaacalib/cpp/src/ipaaca-buffers.cc @@ -476,6 +476,17 @@ IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::v _create_category_listener_if_needed(_uuid); triggerResend = false; } +/*IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::initializer_list<std::string>& category_interests) +:Buffer(basename, "IB") +{ + _channel = __ipaaca_static_option_default_channel; + + for (std::initializer_list<std::string>::const_iterator it=category_interests.begin(); it!=category_interests.end(); ++it) { + _create_category_listener_if_needed(*it); + } + _create_category_listener_if_needed(_uuid); + triggerResend = false; +}*/ IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::string& category_interest1) :Buffer(basename, "IB") { -- GitLab