Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • scs/ipaaca
  • ramin.yaghoubzadeh/ipaaca
2 results
Show changes
Showing
with 7261 additions and 881 deletions
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-definitions.h
*
* \brief Header file for data and exception types and helper functions.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_definitions_h_INCLUDED__
#define __ipaaca_definitions_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
typedef uint32_t revision_t;
/// Type of the IU event. Realized as an integer to enable bit masks for filters. One of: IU_ADDED, IU_COMMITTED, IU_DELETED, IU_RETRACTED, IU_UPDATED, IU_LINKSUPDATED, IU_MESSAGE
typedef uint32_t IUEventType;
#define IU_ADDED 1
#define IU_COMMITTED 2
#define IU_DELETED 4
#define IU_RETRACTED 8
#define IU_UPDATED 16
#define IU_LINKSUPDATED 32
#define IU_MESSAGE 64
/// Bit mask for receiving all IU events \see IUEventType
#define IU_ALL_EVENTS 127
/// Ipaaca (console) log levels
#define IPAACA_LOG_LEVEL_NONE 0
#define IPAACA_LOG_LEVEL_CRITICAL 1
#define IPAACA_LOG_LEVEL_ERROR 2
#define IPAACA_LOG_LEVEL_WARNING 3
#define IPAACA_LOG_LEVEL_INFO 4
#define IPAACA_LOG_LEVEL_DEBUG 5
/// Convert an int event type to a human-readable string
IPAACA_HEADER_EXPORT inline std::string iu_event_type_to_str(IUEventType type)
{
switch(type) {
case IU_ADDED: return "ADDED";
case IU_COMMITTED: return "COMMITTED";
case IU_DELETED: return "DELETED";
case IU_RETRACTED: return "RETRACTED";
case IU_UPDATED: return "UPDATED";
case IU_LINKSUPDATED: return "LINKSUPDATED";
case IU_MESSAGE: return "MESSAGE";
default: return "(NOT A KNOWN SINGLE IU EVENT TYPE)";
}
}
/// IU access mode: PUSH means that updates are broadcast; REMOTE means that reads are RPC calls (currently NOT implemented); MESSAGE means a fire-and-forget message
enum IUAccessMode {
IU_ACCESS_PUSH,
IU_ACCESS_REMOTE,
IU_ACCESS_MESSAGE
};
/// generate a UUID as an ASCII string
IPAACA_HEADER_EXPORT std::string generate_uuid_string();
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-errors.h
*
* \brief Header file for all errors and exceptions
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date February, 2019
*/
#ifndef __ipaaca_errors_h_INCLUDED__
#define __ipaaca_errors_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
/**
* Exception with string description
*/
class Exception: public std::exception//{{{
{
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _description;
public:
IPAACA_HEADER_EXPORT inline Exception(const std::string& description=""): _description(description) { }
IPAACA_HEADER_EXPORT inline ~Exception() throw() { }
IPAACA_HEADER_EXPORT const char* what() const throw() {
return _description.c_str();
}
};//}}}
class Abort: public std::exception//{{{
{
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _description;
public:
IPAACA_HEADER_EXPORT inline Abort(const std::string& description=""): _description(description) { }
IPAACA_HEADER_EXPORT inline ~Abort() throw() { }
IPAACA_HEADER_EXPORT const char* what() const throw() {
return _description.c_str();
}
};//}}}
/// BackEnd failed conditions, e.g. limits
class BackEndBadConditionError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~BackEndBadConditionError() throw() { }
IPAACA_HEADER_EXPORT inline BackEndBadConditionError() { //std::shared_ptr<BackEnd> iu) {
_description = "BackEndBadConditionError";
}
};//}}}
/// BackEnd [hard-]failed to connect a participant
class BackEndConnectionFailedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~BackEndConnectionFailedError() throw() { }
IPAACA_HEADER_EXPORT inline BackEndConnectionFailedError() { //std::shared_ptr<BackEnd> iu) {
_description = "BackEndConnectionFailedError";
}
};//}}}
/// BackEnd not found
class BackEndNotFoundError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~BackEndNotFoundError() throw() { }
IPAACA_HEADER_EXPORT inline BackEndNotFoundError() { //std::shared_ptr<BackEnd> iu) {
_description = "BackEndNotFoundError";
}
};//}}}
/// Unknown wire type encountered
class UnhandledWireTypeError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~UnhandledWireTypeError() throw() { }
IPAACA_HEADER_EXPORT inline UnhandledWireTypeError(int wire_type=-1) {
if (wire_type>0) {
_description = "UnhandledWireTypeError (wire type encountered: " + std::to_string(wire_type) + ")";
} else {
_description = "UnhandledWireTypeError (value not provided)";
}
}
};//}}}
/// IU was not found in a buffer
class IUNotFoundError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUNotFoundError() throw() { }
IPAACA_HEADER_EXPORT inline IUNotFoundError() { //std::shared_ptr<IU> iu) {
_description = "IUNotFoundError";
}
};//}}}
/// IU was already published
class IUPublishedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUPublishedError() throw() { }
IPAACA_HEADER_EXPORT inline IUPublishedError() {
_description = "IUPublishedError";
}
};//}}}
/// IU had already been committed to
class IUCommittedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUCommittedError() throw() { }
IPAACA_HEADER_EXPORT inline IUCommittedError() {
_description = "IUCommittedError";
}
};//}}}
/// IU had already been retracted
class IURetractedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IURetractedError() throw() { }
IPAACA_HEADER_EXPORT inline IURetractedError() {
_description = "IURetractedError";
}
};//}}}
/// Remote IU update failed because it had been modified in the mean time
class IUUpdateFailedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUUpdateFailedError() throw() { }
IPAACA_HEADER_EXPORT inline IUUpdateFailedError() {
_description = "IUUpdateFailedError";
}
};//}}}
/// Requested resend of old IU due to malformed channel specification
class IUResendRequestFailedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUResendRequestFailedError() throw() { }
IPAACA_HEADER_EXPORT inline IUResendRequestFailedError() {
_description = "IUResendRequestFailedError";
}
};//}}}
/// Write operation failed because IU had been set read-only
class IUReadOnlyError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUReadOnlyError() throw() { }
IPAACA_HEADER_EXPORT inline IUReadOnlyError() {
_description = "IUReadOnlyError";
}
};//}}}
/// Buffer::add() failed because the IU had been previously placed in another buffer
class IUAlreadyInABufferError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUAlreadyInABufferError() throw() { }
IPAACA_HEADER_EXPORT inline IUAlreadyInABufferError() {
_description = "IUAlreadyInABufferError";
}
};//}}}
/// A request was made that is only valid for an already published IU
class IUUnpublishedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUUnpublishedError() throw() { }
IPAACA_HEADER_EXPORT inline IUUnpublishedError() {
_description = "IUUnpublishedError";
}
};//}}}
/// IU had already been allocated a UID
class IUAlreadyHasAnUIDError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUAlreadyHasAnUIDError() throw() { }
IPAACA_HEADER_EXPORT inline IUAlreadyHasAnUIDError() {
_description = "IUAlreadyHasAnUIDError";
}
};//}}}
/// IU had already been allocated an owner name
class IUAlreadyHasAnOwnerNameError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUAlreadyHasAnOwnerNameError() throw() { }
IPAACA_HEADER_EXPORT inline IUAlreadyHasAnOwnerNameError() {
_description = "IUAlreadyHasAnOwnerNameError";
}
};//}}}
/// UID generation failed (Windows only)
class UUIDGenerationError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~UUIDGenerationError() throw() { }
IPAACA_HEADER_EXPORT inline UUIDGenerationError() {
_description = "UUIDGenerationError";
}
};//}}}
/// Not implemented (e.g. invalid request parameters via backend)
class NotImplementedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~NotImplementedError() throw() { }
IPAACA_HEADER_EXPORT inline NotImplementedError() {
_description = "NotImplementedError";
}
};//}}}
/// PayloadEntryProxy requested type conversion failed (including lenient interpretation)
class PayloadTypeConversionError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadTypeConversionError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadTypeConversionError() {
_description = "PayloadTypeConversionError";
}
};//}}}
/// PayloadEntryProxy was addressed as list when not a list or as map when not a map
class PayloadAddressingError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadAddressingError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadAddressingError() {
_description = "PayloadAddressingError";
}
};//}}}
/// Malformed json was received for a Payload
class JsonParsingError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~JsonParsingError() throw() { }
IPAACA_HEADER_EXPORT inline JsonParsingError() {
_description = "JsonParsingError";
}
};//}}}
/// PayloadEntryProxy invalidated (unused)
class PayloadEntryProxyInvalidatedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadEntryProxyInvalidatedError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadEntryProxyInvalidatedError() {
_description = "PayloadEntryProxyInvalidatedError";
}
};//}}}
/// Iterator over Payload entries was invalidated by an intermediate IU update operation
class PayloadIteratorInvalidError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadIteratorInvalidError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadIteratorInvalidError() {
_description = "PayloadIteratorInvalidError";
}
};//}}}
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-forwards.h
*
* \brief Header file for forward definitions.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_forwards_h_INCLUDED__
#define __ipaaca_forwards_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
/*
* forward declarations
*/
namespace backend {
//class Scope;
class Event;
class Informer;
class Listener;
class LocalServer;
class RemoteServer;
} // of namespace backend
class PayloadDocumentEntry;
class PayloadBatchUpdateLock;
class PayloadEntryProxy;
class Payload;
class PayloadIterator;
class IUInterface;
class IU;
class Message;
class RemotePushIU;
class RemoteMessage;
class IULinkUpdate;
class IUPayloadUpdate;
class IUStore;
class FrozenIUStore;
class Buffer;
class InputBuffer;
class OutputBuffer;
class CallbackIUPayloadUpdate;
class CallbackIULinkUpdate;
class CallbackIUCommission;
class CallbackIUResendRequest;
class CallbackIURetraction;
class IUConverter;
class MessageConverter;
class IUPayloadUpdateConverter;
class IULinkUpdateConverter;
//class IntConverter;
class BufferConfiguration;
class BufferConfigurationBuilder;
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-initializer.h
*
* \brief Header file for the global initializer unit
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date February, 2019
*/
#ifndef __ipaaca_initializer_h_INCLUDED__
#define __ipaaca_initializer_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
/** \brief Static library initialization for backend
*
* This static class (singleton) is called once (explicitly or on-demand).
* Unless called manually, it is initialized when ipaaca is first used
* (i.e. the first Buffer is created).
*/
class Initializer
{
public:
/// Initialize the backend [DEPRECATED] (old name, use initialize_backend() instead)
[[deprecated("Use initialize_backend() instead")]]
IPAACA_HEADER_EXPORT static void initialize_ipaaca_rsb_if_needed();
/// Explicitly initialize the backend (usually not required). No effect if already initialized. Automatically called during first Buffer construction.
IPAACA_HEADER_EXPORT static void initialize_backend();
IPAACA_HEADER_EXPORT static bool initialized();
IPAACA_HEADER_EXPORT static void dump_current_default_config();
protected:
/** Perform rsb pre-setup before the implicit initialization
* (when first instantiating something). Pre-setup includes
* finding the RSB plugin dir, looking through several parent
* directories for a path "deps/lib/rsb*"/plugins. The path
* can also be set directly (env var RSB_PLUGINS_CPP_PATH),
* which disables the automatic search.
*/
IPAACA_HEADER_EXPORT static void override_env_with_cmdline_set_variables();
IPAACA_MEMBER_VAR_EXPORT static bool _initialized;
};
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-ius.h
*
* \brief Header file for IU (incremental unit) classes.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_ius_h_INCLUDED__
#define __ipaaca_ius_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#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.
*
*/
class IUInterface {//{{{
friend class ipaaca::converters::IUConverter;
//friend class ipaaca::converters::MessageConverter;
friend std::ostream& operator<<(std::ostream& os, const IUInterface& obj);
protected:
IPAACA_HEADER_EXPORT IUInterface();
public:
IPAACA_HEADER_EXPORT inline virtual ~IUInterface() { }
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _uid;
IPAACA_MEMBER_VAR_EXPORT revision_t _revision;
IPAACA_MEMBER_VAR_EXPORT std::string _category;
IPAACA_MEMBER_VAR_EXPORT std::string _payload_type; // default is taken from __ipaaca_static_option_default_payload_type
IPAACA_MEMBER_VAR_EXPORT std::string _owner_name;
IPAACA_MEMBER_VAR_EXPORT bool _committed;
IPAACA_MEMBER_VAR_EXPORT bool _retracted;
IPAACA_MEMBER_VAR_EXPORT IUAccessMode _access_mode;
IPAACA_MEMBER_VAR_EXPORT bool _read_only;
//std::shared_ptr<Buffer> _buffer;
IPAACA_MEMBER_VAR_EXPORT Buffer* _buffer;
IPAACA_MEMBER_VAR_EXPORT SmartLinkMap _links;
protected:
friend class Payload;
// Internal functions that perform the update logic,
// e.g. sending a notification across the network
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) = 0;
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name) = 0;
//void _set_buffer(std::shared_ptr<Buffer> buffer);
IPAACA_HEADER_EXPORT void _associate_with_buffer(Buffer* buffer);
IPAACA_HEADER_EXPORT void _set_buffer(Buffer* buffer);
IPAACA_HEADER_EXPORT void _set_uid(const std::string& uid);
IPAACA_HEADER_EXPORT void _set_owner_name(const std::string& owner_name);
protected:
// internal functions that do not emit update events
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 been retracted
IPAACA_HEADER_EXPORT inline bool retracted() const { return _retracted; }
/// 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 std::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(std::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 std::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.
*/
class IU: public IUInterface {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class ipaaca::backend::LocalServer;
public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected:
IPAACA_MEMBER_VAR_EXPORT Lock _revision_lock;
protected:
IPAACA_HEADER_EXPORT inline void _increase_revision_number() { _revision++; }
IPAACA_HEADER_EXPORT IU(const std::string& category, IUAccessMode access_mode=IU_ACCESS_PUSH, bool read_only=false, const std::string& payload_type="" ); // __ipaaca_static_option_default_payload_type
public:
IPAACA_HEADER_EXPORT inline ~IU() {
}
[[deprecated("Please use the new argument order: category, payload_type, read_only")]]
IPAACA_HEADER_EXPORT static std::shared_ptr<IU> create(const std::string& category, IUAccessMode access_mode, bool read_only=false, const std::string& payload_type="" );
IPAACA_HEADER_EXPORT static std::shared_ptr<IU> create(const std::string& category, const std::string& payload_type="", bool read_only=false);
IPAACA_HEADER_EXPORT inline Payload& payload() _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT void commit() _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT virtual void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT virtual void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT virtual void _internal_commit(const std::string& writer_name = "");
public:
typedef std::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
*/
class Message: public IU {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class ipaaca::backend::LocalServer;
protected:
IPAACA_HEADER_EXPORT Message(const std::string& category, IUAccessMode access_mode=IU_ACCESS_MESSAGE, bool read_only=true, const std::string& payload_type="" );
public:
IPAACA_HEADER_EXPORT inline ~Message() {
}
[[deprecated("Please use the new argument order: category, payload_type")]]
IPAACA_HEADER_EXPORT static std::shared_ptr<Message> create(const std::string& category, IUAccessMode access_mode, bool read_only=true, const std::string& payload_type="" );
IPAACA_HEADER_EXPORT static std::shared_ptr<Message> create(const std::string& category, const std::string& payload_type="");
protected:
IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _internal_commit(const std::string& writer_name = "");
public:
typedef std::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.
class RemotePushIU: public IUInterface {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class ipaaca::converters::IUConverter;
//friend class ipaaca::converters::MessageConverter;
public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected:
IPAACA_HEADER_EXPORT RemotePushIU();
IPAACA_HEADER_EXPORT static std::shared_ptr<RemotePushIU> create();
public:
IPAACA_HEADER_EXPORT inline ~RemotePushIU() {
}
IPAACA_HEADER_EXPORT inline Payload& payload() _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT void commit() _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _apply_update(IUPayloadUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_commission();
IPAACA_HEADER_EXPORT void _apply_retraction();
typedef std::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.
class RemoteMessage: public IUInterface {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class ipaaca::converters::IUConverter;
//friend class ipaaca::converters::MessageConverter;
public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected:
IPAACA_HEADER_EXPORT RemoteMessage();
IPAACA_HEADER_EXPORT static std::shared_ptr<RemoteMessage> create();
public:
IPAACA_HEADER_EXPORT inline ~RemoteMessage() {
}
IPAACA_HEADER_EXPORT inline Payload& payload() _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT void commit() _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _apply_update(IUPayloadUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_commission();
IPAACA_HEADER_EXPORT void _apply_retraction();
typedef std::shared_ptr<RemoteMessage> ptr;
};//}}}
#ifdef IPAACA_BUILD_MOCK_OBJECTS
/// Mock IU for testing purposes. [INTERNAL]
class FakeIU: public IUInterface {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class ipaaca::converters::IUConverter;
//friend class ipaaca::converters::MessageConverter;
protected:
IPAACA_MEMBER_VAR_EXPORT Payload _payload;
IPAACA_HEADER_EXPORT FakeIU();
public:
IPAACA_HEADER_EXPORT static std::shared_ptr<FakeIU> create();
IPAACA_HEADER_EXPORT ~FakeIU();
IPAACA_HEADER_EXPORT Payload& payload() _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT const Payload& const_payload() const _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void commit() _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void add_fake_payload_item(const std::string& key, PayloadDocumentEntry::ptr entry);
protected:
IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _apply_update(IUPayloadUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_commission();
IPAACA_HEADER_EXPORT void _apply_retraction();
public:
typedef std::shared_ptr<FakeIU> ptr;
};//}}}
#endif
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-locking.h
*
* \brief Header file for locking / mutexes.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_locking_h_INCLUDED__
#define __ipaaca_locking_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
/// Reentrant lock/mutex class
class Lock
{
protected:
std::recursive_mutex _mutex;
public:
IPAACA_HEADER_EXPORT inline Lock() {
}
IPAACA_HEADER_EXPORT inline ~Lock() {
}
IPAACA_HEADER_EXPORT inline void lock() {
_mutex.lock();
on_lock();
}
IPAACA_HEADER_EXPORT inline void unlock() {
on_unlock();
_mutex.unlock();
}
IPAACA_HEADER_EXPORT virtual inline void on_lock() {
}
IPAACA_HEADER_EXPORT virtual inline void on_unlock() {
}
};
/** \brief Stack-based lock holder.
*
* Stack-based lock holder. Create in a new stack frame
* (i.e. {}-block) and it will obtain the lock and
* auto-release in on exiting the stack frame.
*/
class Locker
{
protected:
IPAACA_MEMBER_VAR_EXPORT Lock* _lock;
private:
IPAACA_HEADER_EXPORT inline Locker(): _lock(NULL) { } // not available
public:
IPAACA_HEADER_EXPORT inline Locker(Lock& lock): _lock(&lock) {
_lock->lock();
}
IPAACA_HEADER_EXPORT inline ~Locker() {
_lock->unlock();
}
};
/** \brief Locker for existing pthread mutexes.
*
* Stack-based lock holder for existing pthread_mutex_t mutexes.
*
* \see Locker
*/
#if _WIN32 || _WIN64
// nothing for Windows
#else
#include <pthread.h>
class PthreadMutexLocker
{
protected:
IPAACA_MEMBER_VAR_EXPORT pthread_mutex_t* _lock;
private:
IPAACA_HEADER_EXPORT inline PthreadMutexLocker(): _lock(NULL) { } // not available
public:
IPAACA_HEADER_EXPORT inline PthreadMutexLocker(pthread_mutex_t* lock): _lock(lock) {
if (!lock) throw Exception("PthreadMutexLocker got a NULL mutex!");
pthread_mutex_lock(_lock);
}
IPAACA_HEADER_EXPORT inline ~PthreadMutexLocker() {
pthread_mutex_unlock(_lock);
}
};
#endif
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-payload.h
*
* \brief Header file for IU payload functionality.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_payload_h_INCLUDED__
#define __ipaaca_payload_h_INCLUDED__
#include <typeinfo>
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#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.
template<typename T> T json_value_cast(const rapidjson::Value&);
template<typename T> T json_value_cast(const rapidjson::Value* value) { if (!value) return T(); return json_value_cast<T>(*value); }
template<> IPAACA_HEADER_EXPORT long json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT int json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT double json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT bool json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT std::string json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT std::vector<std::string> json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT std::list<std::string> json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT std::map<std::string, std::string> json_value_cast(const rapidjson::Value&);
// 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
/// Setter to store a vector of supported basic types into json value, used by PayloadEntryProxy.
template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::vector<T>& ts)
{
valueobject.SetArray();
for (auto& val: ts) {
rapidjson::Value newv;
pack_into_json_value(newv, allocator, val);
valueobject.PushBack(newv, allocator);
}
}
/// Setter to store a list of supported basic types into json value, used by PayloadEntryProxy.
template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::list<T>& ts)
{
valueobject.SetArray();
for (auto& val: ts) {
rapidjson::Value newv;
pack_into_json_value(newv, allocator, val);
valueobject.PushBack(newv, allocator);
}
}
/// Setter to store a map of string -> supported basic types into json value, used by PayloadEntryProxy.
template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::map<std::string, T>& ts)
{
valueobject.SetObject();
for (auto& val: ts) {
rapidjson::Value key;
key.SetString(val.first, allocator);
rapidjson::Value newv;
pack_into_json_value(newv, allocator, val.second);
valueobject.AddMember(key, newv, allocator);
}
}
/// Single payload entry wrapping a rapidjson::Document with some conversion glue. Also handles copy-on-write Document cloning. <b>Internal type</b> - users generally do not see this.
class PayloadDocumentEntry//{{{
{
friend std::ostream& operator<<(std::ostream& os, std::shared_ptr<PayloadDocumentEntry> entry);
public:
IPAACA_MEMBER_VAR_EXPORT ipaaca::Lock lock;
IPAACA_MEMBER_VAR_EXPORT bool modified;
IPAACA_MEMBER_VAR_EXPORT rapidjson::Document document;
IPAACA_HEADER_EXPORT inline PayloadDocumentEntry(): modified(false) { }
IPAACA_HEADER_EXPORT inline ~PayloadDocumentEntry() { }
IPAACA_HEADER_EXPORT std::string to_json_string_representation();
IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> from_json_string_representation(const std::string& input);
IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> from_unquoted_string_value(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;
};
//}}}
typedef std::map<std::string, PayloadDocumentEntry::ptr> PayloadDocumentStore;
/** \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.
*/
class Payload: public Lock //{{{
{
friend std::ostream& operator<<(std::ostream& os, const Payload& obj);
friend class IUInterface;
friend class IU;
friend class Message;
friend class RemotePushIU;
friend class RemoteMessage;
friend class ipaaca::converters::IUConverter;
//friend class ipaaca::converters::MessageConverter;
friend class ipaaca::backend::LocalServer;
friend class PayloadEntryProxy;
friend class PayloadIterator;
friend class FakeIU;
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _owner_name;
IPAACA_MEMBER_VAR_EXPORT PayloadDocumentStore _document_store;
IPAACA_MEMBER_VAR_EXPORT std::weak_ptr<IUInterface> _iu;
IPAACA_MEMBER_VAR_EXPORT Lock _payload_operation_mode_lock; //< enforcing atomicity wrt the bool flag below
IPAACA_MEMBER_VAR_EXPORT bool _update_on_every_change; //< true: batch update not active; false: collecting updates (payload locked)
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, PayloadDocumentEntry::ptr> _collected_modifications;
IPAACA_MEMBER_VAR_EXPORT std::vector<std::string> _collected_removals; // TODO use set later? cf. IU, too
IPAACA_MEMBER_VAR_EXPORT std::string _batch_update_writer_name;
protected:
/// inherited from ipaaca::Lock, starting batch update collection mode
IPAACA_HEADER_EXPORT void on_lock() override;
/// inherited from ipaaca::Lock, finishing batch update collection mode
IPAACA_HEADER_EXPORT void on_unlock() override;
/// thread ID for current write access (to let that thread read from cache and others from old payload)
IPAACA_MEMBER_VAR_EXPORT std::string _writing_thread_id;
protected:
IPAACA_HEADER_EXPORT void initialize(std::shared_ptr<IUInterface> iu);
IPAACA_HEADER_EXPORT inline void _set_owner_name(const std::string& name) { _owner_name = name; }
IPAACA_HEADER_EXPORT void _remotely_enforced_wipe();
IPAACA_HEADER_EXPORT void _remotely_enforced_delitem(const std::string& k);
IPAACA_HEADER_EXPORT void _remotely_enforced_setitem(const std::string& k, PayloadDocumentEntry::ptr entry);
IPAACA_HEADER_EXPORT void _internal_replace_all(const std::map<std::string, PayloadDocumentEntry::ptr>& new_contents, const std::string& writer_name="");
IPAACA_HEADER_EXPORT void _internal_merge(const std::map<std::string, PayloadDocumentEntry::ptr>& contents_to_merge, const std::string& writer_name="");
IPAACA_HEADER_EXPORT void _internal_set(const std::string& k, PayloadDocumentEntry::ptr v, const std::string& writer_name="");
IPAACA_HEADER_EXPORT void _internal_remove(const std::string& k, const std::string& writer_name="");
IPAACA_HEADER_EXPORT void _internal_merge_and_remove(const std::map<std::string, PayloadDocumentEntry::ptr>& contents_to_merge, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="");
public:
IPAACA_HEADER_EXPORT inline Payload(): _batch_update_writer_name(""), _update_on_every_change(true) { }
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>();
/// remove a single payload entry
IPAACA_HEADER_EXPORT inline void remove(const std::string& k) { _internal_remove(k); }
/// 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:
/// set or overwrite a single payload entry with a PayloadDocumentEntry object (used by PayloadEntryProxy::operator=()).
IPAACA_HEADER_EXPORT inline void set(const std::string& k, PayloadDocumentEntry::ptr entry) { _internal_set(k, entry); }
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);
protected:
IPAACA_MEMBER_VAR_EXPORT unsigned long internal_revision;
IPAACA_MEMBER_VAR_EXPORT inline void mark_revision_change() { internal_revision++; }
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 std::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>
*
*/
class PayloadIterator//{{{
{
friend class Payload;
friend std::ostream& operator<<(std::ostream& os, const PayloadIterator& iter);
protected:
IPAACA_MEMBER_VAR_EXPORT Payload* _payload;
IPAACA_MEMBER_VAR_EXPORT unsigned long reference_payload_revision;
IPAACA_MEMBER_VAR_EXPORT PayloadDocumentStore::iterator raw_iterator;
protected:
IPAACA_HEADER_EXPORT PayloadIterator(Payload* payload, PayloadDocumentStore::iterator&& pl_iter ); //, bool is_end);
public:
IPAACA_HEADER_EXPORT PayloadIterator(const PayloadIterator& iter);
IPAACA_HEADER_EXPORT PayloadIterator& 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 PayloadIterator& ref);
IPAACA_HEADER_EXPORT bool operator!=(const PayloadIterator& ref);
};
//}}}
/// Iterator over a payload entry that is a json map-type object (returned type during dereferencing: pair<string, PayloadEntryProxy>)
class PayloadEntryProxyMapIterator//{{{
{
public:
typedef rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>::ConstMemberIterator 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);
};
//}}}
/// Iterator over a payload entry that is a json list-type object (returned type during dereferencing: PayloadEntryProxy)
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);
};
//}}}
/// Interpretation of a variant json value as a map-type object
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;
};
//}}}
/// Interpretation of a variant json value as a list-type object
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;
};
//}}}
/** \brief Reference to an existent or nonexistent payload entry (or a value deeper in the json tree) - examples below:
*
* 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 (reading):
*
* <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>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_pair: 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)
*
* \b Examples (writing):
*
* <code>iu->payload()["my_new_item"] = "new value";</code> // most basic operation, set string value
*
* <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>iu->payload()["name_list"].push_back("--- adding some numbers below ---");</code> // append a supported value to an existing list
*
* <code>iu->payload()["name_list"].extend(iu->payload()["double_list"]);</code> // extend list by items; \b Note: all setters also accept proxies as source values, creating copies of values
*/
class PayloadEntryProxy//{{{
{
friend class Payload;
friend class PayloadIterator;
friend class PayloadDocumentEntry;
friend class PayloadEntryProxyListDecorator;
friend class PayloadEntryProxyListIterator;
friend class PayloadEntryProxyMapDecorator;
friend class PayloadEntryProxyMapIterator;
friend std::ostream& operator<<(std::ostream& os, const PayloadEntryProxy& proxy);
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();
protected:
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 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 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; ///< json value that corresponds to the current navigation (or nullptr)
protected:
// set internal json value object
void set_json_value(rapidjson::Value* json_value, const std::string& diag) {
IPAACA_DEBUG("Set json_value of " << _key << " to ptr " << (off_t) json_value << " - reason: " << diag)
this->json_value = json_value;
}
// 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
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;
}
/// 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
template<typename T> bool operator==(T othervalue)
{
if (!json_value) return false;
try {
return json_value_cast<T>(*json_value) == othervalue;
} catch(PayloadTypeConversionError& ex) {
// assume conversion error = type mismatch = unequal
return false;
}
}
/// Value comparison with supported basic types
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);
/// Conversion to std::string (explicit or implicit)
IPAACA_HEADER_EXPORT operator std::string();
/// Conversion to int (explicit or implicit)
IPAACA_HEADER_EXPORT operator int();
/// 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
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;
}
/// Conversion to uniform std::list of supported basic type
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;
}
/// Conversion to uniform std::map of string -> supported basic type
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;
}
// TODO maybe remove these deprecated converters later
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator std::string() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT std::string to_str();
//long to_int() { return operator long(); ;
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator int() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT int to_int();
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator long() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT long to_long();
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator double() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT double to_float();
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator double() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT double to_double();
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator bool() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT bool to_bool();
/// Append a supported type to a list-type payload value
template<typename T> void push_back(T t)
{
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& list = new_entry->get_or_create_nested_value_from_proxy_path(this);
rapidjson::Value newval;
pack_into_json_value(newval, new_entry->document.GetAllocator(), t);
list.PushBack(newval, new_entry->document.GetAllocator());
_payload->set(_key, new_entry);
}
/// Append the value of another proxy (or a null value) to a list-type value
IPAACA_HEADER_EXPORT void push_back(const PayloadEntryProxy& otherproxy)
{
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& list = new_entry->get_or_create_nested_value_from_proxy_path(this);
rapidjson::Value newval;
auto valueptr = otherproxy.json_value;
if (valueptr) { // only set if value is valid, keep default null value otherwise
newval.CopyFrom(*valueptr, new_entry->document.GetAllocator());
}
list.PushBack(newval, new_entry->document.GetAllocator());
_payload->set(_key, new_entry);
}
/// Extend a list-type payload value with a vector containing items of a supported type
template<typename T> void extend(const std::vector<T>& ts)
{
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& list = new_entry->get_or_create_nested_value_from_proxy_path(this);
for (auto& t: ts) {
rapidjson::Value newval;
pack_into_json_value(newval, new_entry->document.GetAllocator(), t);
list.PushBack(newval, new_entry->document.GetAllocator());
}
_payload->set(_key, new_entry);
}
/// Extend a list-type payload value with a list containing items of a supported type
template<typename T> void extend(const std::list<T>& ts)
{
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& list = new_entry->get_or_create_nested_value_from_proxy_path(this);
for (auto& t: ts) {
rapidjson::Value newval;
pack_into_json_value(newval, new_entry->document.GetAllocator(), t);
list.PushBack(newval, new_entry->document.GetAllocator());
}
_payload->set(_key, new_entry);
}
/// Extend a list-type payload value with items (copies) from another list-type value
IPAACA_HEADER_EXPORT void extend(const PayloadEntryProxy& otherproxy)
{
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
if ((!otherproxy.json_value) || (!(otherproxy.json_value->IsArray()))) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& list = new_entry->get_or_create_nested_value_from_proxy_path(this);
for (size_t i=0; i<otherproxy.json_value->Size(); ++i) {
rapidjson::Value newval;
rapidjson::Value& value = (*(otherproxy.json_value))[i];
newval.CopyFrom(value, new_entry->document.GetAllocator());
list.PushBack(newval, new_entry->document.GetAllocator());
}
_payload->set(_key, new_entry);
}
};
//}}}
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-string_utils.h
*
* \brief Header file for data and exception types and helper functions.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_string_utils_h_INCLUDED__
#define __ipaaca_string_utils_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
// in ipaaca-string-utils.cc
// additional misc functions ( String splitting / joining )//{{{
IPAACA_HEADER_EXPORT std::string str_trim(const std::string &s);
IPAACA_HEADER_EXPORT std::string str_join(const std::set<std::string>& set,const std::string& sep);
IPAACA_HEADER_EXPORT std::string str_join(const std::vector<std::string>& vec,const std::string& sep);
IPAACA_HEADER_EXPORT int str_split_wipe(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters );
IPAACA_HEADER_EXPORT int str_split_append(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters );
//}}}
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2013 Sociable Agents Group
* CITEC, Bielefeld University
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
......@@ -21,7 +22,7 @@
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
......@@ -30,40 +31,147 @@
* Excellence Initiative.
*/
#ifndef __IPAACA_H__
#define __IPAACA_H__
/**
* \file ipaaca.h
*
* \brief Central header file for IPAACA-C++.
*
* This is the central header file for the C++ version of IPAACA. Users should <b>include this file only.</b>
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
/**
\mainpage Documentation for IPAACA-C++
This is the automatically generated documentation for the C++ implementation of IPAACA.
Protocol version: $(IPAACA_PROTOCOL_VERSION_MAJOR).$(IPAACA_PROTOCOL_VERSION_MINOR) \n
Release number: $(IPAACA_CPP_RELEASE_NUMBER) \n
Release date: $(IPAACA_CPP_RELEASE_DATE)
<b>IPAACA, the Incremental Processing Architecture for Artificial Conversational Agents, is available via <a href="https://opensource.cit-ec.de/projects/ipaaca/wiki"><b>its project page on CITEC Open Source</b></a>.</b>
IPAACA is (c) 2009-2022 Social Cognitive Systems Group, CITEC, Bielefeld University, Germany
The corresponding maintainer of this C++ version is Ramin Yaghoubzadeh Torky, ryaghoubzadeh@uni-bielefeld.de
<h3>List of most relevant entry points for application developers:</h3>
Buffers: InputBuffer, OutputBuffer
IUs: IUInterface, IU, Message
IU handling (user-set): #IUEventHandlerFunction
IU payload contents: Payload, PayloadEntryProxy
<h3>Short examples:</h3>
<h4>Encapsulated listener</h4>
<pre>
#include <ipaaca/ipaaca.h>
class ReceiverCpp {
public:
void handle_iu_inbuf(ipaaca::IUInterface::ptr iu, ipaaca::IUEventType etype, bool local)
{
// Inspect category and IUEventType (ADDED, UPDATED...)
std::cout << ipaaca::iu_event_type_to_str(etype) << " category=" << iu->category() << " uid=" << iu->uid() << std::endl;
// Access payload
for (auto kv : iu->payload()) {
std::cout << "Payload entry '" << kv.first << "': " << ((std::string) kv.second) << std::endl;
}
// Access any links
auto links = iu->get_all_links();
for (auto kv : iu->get_all_links()) {
std::cout << "'" << kv.first << "' links to these IUs: ";
for (const auto& lnk : kv.second) {
std::cout << lnk << " ";
}
std::cout << std::endl;
}
}
int run()
{
auto ib = ipaaca::InputBuffer::create("myRecvProgName", std::set<std::string>{"myCategory"});
ib->register_handler(IPAACA_BIND_CLASS_HANDLER(&ReceiverCpp::handle_iu_inbuf, this)) // bind to member
std::cout << "Listening for all IU events (until Ctrl-C) ..." << std::endl;
while (true) {
sleep(5);
}
return 0;
}
};
int main(int argc, char** argv)
{
ipaaca::__ipaaca_static_option_log_level = IPAACA_LOG_LEVEL_DEBUG; // if you want this
ReceiverCpp rcpp;
rcpp.run();
}
</pre>
<h4>Minimal sender</h4>
<pre>
#include <ipaaca/ipaaca.h>
int main(int argc, char** argv)
{
auto out_buf = ipaaca::OutputBuffer::create("myProgramName");
auto iu = ipaaca::Message::create("myCategory");
iu->payload()["test"] = 123; // NOTE: see also #PayloadEntryProxy
out_buf->add(iu); // will be broadcast now
return 0;
}
</pre>
*/
#ifndef __ipaaca_h_INCLUDED__
#define __ipaaca_h_INCLUDED__
/// ipaaca/IU/RSB protocol major version number
#define IPAACA_PROTOCOL_VERSION_MAJOR 1
#define IPAACA_PROTOCOL_VERSION_MAJOR 4
/// ipaaca/IU/RSB protocol minor version number
#define IPAACA_PROTOCOL_VERSION_MINOR 0
#define IPAACA_PROTOCOL_VERSION_MINOR 1
/// running release number of ipaaca-c++
#define IPAACA_CPP_RELEASE_NUMBER 11
#define IPAACA_CPP_RELEASE_NUMBER 17
/// date of last release number increment
#define IPAACA_CPP_RELEASE_DATE "2014-02-10"
#define IPAACA_CPP_RELEASE_DATE "2019-02-14"
#ifndef __FUNCTION_NAME__
#ifdef WIN32 // Windows
#if _WIN32 || _WIN64 // Windows
#define __FUNCTION_NAME__ __FUNCTION__
#else // POSIX
#define __FUNCTION_NAME__ __func__
#endif
#endif
#if defined (_WIN32)
#if defined(ipaaca_EXPORTS)
#define IPAACA_EXPORT
// __declspec(dllexport)
#define IPAACA_HEADER_EXPORT __declspec(dllexport)
#define IPAACA_MEMBER_VAR_EXPORT
// __declspec(dllexport)
#if _WIN32 || _WIN64
#define IPAACA_SYSTEM_DEPENDENT_CLASS_NAME(c) "class "##c
#else
#define IPAACA_SYSTEM_DEPENDENT_CLASS_NAME(c) c
#endif
#if _WIN32 || _WIN64
#if defined(IPAACA_STATIC_BINARY)
#define IPAACA_EXPORT
#define IPAACA_HEADER_EXPORT
#define IPAACA_MEMBER_VAR_EXPORT
#else
#define IPAACA_EXPORT
// __declspec(dllimport)
#define IPAACA_HEADER_EXPORT __declspec(dllimport)
#define IPAACA_MEMBER_VAR_EXPORT
// __declspec(dllimport)
#if defined(ipaaca_EXPORTS)
#define IPAACA_EXPORT
#define IPAACA_HEADER_EXPORT __declspec(dllexport)
#define IPAACA_MEMBER_VAR_EXPORT
#else
#define IPAACA_EXPORT
#define IPAACA_HEADER_EXPORT __declspec(dllimport)
#define IPAACA_MEMBER_VAR_EXPORT
#endif
#endif
#else
#define IPAACA_EXPORT
......@@ -71,34 +179,49 @@
#define IPAACA_MEMBER_VAR_EXPORT
#endif
// retrieve basename of source files for more readable logging
#define __FILE_BASENAME__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/')+1 : __FILE__)
#if _WIN32 || _WIN64
#define _IPAACA_LOG_COLOR_NORMAL ""
#define _IPAACA_LOG_COLOR_DEBUG ""
#define _IPAACA_LOG_COLOR_WARN ""
#define _IPAACA_LOG_COLOR_ERROR ""
#else
#define _IPAACA_LOG_COLOR_NORMAL "\033[m"
#define _IPAACA_LOG_COLOR_DEBUG "\033[37m"
#define _IPAACA_LOG_COLOR_WARN "\033[38;5;208m"
#define _IPAACA_LOG_COLOR_ERROR "\033[38;5;196m"
#endif
#ifdef IPAACA_DEBUG_MESSAGES
#define IPAACA_INFO(i) std::cout << __FILE__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- " << i << std::endl;
#define IPAACA_WARNING(i) std::cout << __FILE__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- WARNING: " << i << std::endl;
#define IPAACA_IMPLEMENT_ME std::cout << __FILE__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- IMPLEMENT ME" << std::endl;
#define IPAACA_TODO(i) std::cout << __FILE__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- TODO: " << i << std::endl;
// Full debug messages mode
#define IPAACA_DEBUG(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_DEBUG) { std::cout << _IPAACA_LOG_COLOR_DEBUG << "[Debug] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- " << i << _IPAACA_LOG_COLOR_NORMAL << std::endl; }
#define IPAACA_IMPLEMENT_ME if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_INFO) { std::cout << "[Info] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- IMPLEMENT ME" << std::endl; }
#define IPAACA_TODO(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_INFO) { std::cout << "[Info] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- TODO: " << i << std::endl; }
#else
#define IPAACA_INFO(i) ;
#define IPAACA_WARNING(i) ;
#define IPAACA_DEBUG(i) ;
#define IPAACA_IMPLEMENT_ME ;
#define IPAACA_TODO(i) ;
#endif
#ifdef IPAACA_EXPOSE_FULL_RSB_API
#include <rsc/runtime/TypeStringTools.h>
#include <rsb/Factory.h>
#include <rsb/Handler.h>
#include <rsb/Event.h>
#include <rsb/ParticipantConfig.h>
#include <rsb/converter/Repository.h>
#include <rsb/converter/ProtocolBufferConverter.h>
#include <rsb/converter/Converter.h>
#include <rsb/rsbexports.h>
#endif
// Always compile in info and above, even if debug messages disabled.
// You can set __ipaaca_static_option_log_level (e.g. IPAACA_LOG_LEVEL_NONE for silence).
#define IPAACA_INFO(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_INFO) { std::cout << "[Info] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- " << i << std::endl; }
#define IPAACA_WARNING(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_WARNING) { std::cout << _IPAACA_LOG_COLOR_WARN << "[WARN] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- WARNING: " << i << _IPAACA_LOG_COLOR_NORMAL << std::endl; }
#define IPAACA_ERROR(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_ERROR) { std::cout << _IPAACA_LOG_COLOR_ERROR << "[ERROR] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- ERROR: " << i << _IPAACA_LOG_COLOR_NORMAL << std::endl; }
#define IPAACA_CRITICAL(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_CRITICAL) { std::cout << _IPAACA_LOG_COLOR_ERROR << "[CRITICAL] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- CRITICAL: " << i << _IPAACA_LOG_COLOR_NORMAL << std::endl; }
// new json-based payload API, used in several classes
#define RAPIDJSON_HAS_STDSTRING 1
#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include <cstdio>
/// marking pure virtual functions for extra readability
#define _IPAACA_ABSTRACT_
#define _IPAACA_OVERRIDE_ override
/// value to return when reading nonexistant payload keys
#define IPAACA_PAYLOAD_DEFAULT_STRING_VALUE ""
......@@ -107,871 +230,116 @@
#include <iostream>
#include <fstream>
// for logger
#include <iomanip>
#ifdef WIN32
#if _WIN32 || _WIN64
// for Windows
// time
#include <time.h>
// and env
#define IPAACA_SETENV(k, v) _putenv_s(k, v);
#else
// for Linux and OS X
// for Linux and MacOS
// time
#include <sys/time.h>
// and env
#define IPAACA_SETENV(k, v) setenv(k, v, 1);
#endif
#ifndef Q_MOC_RUN
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/pointer_cast.hpp>
#include <boost/lexical_cast.hpp>
#endif
#include <cstdlib>
#include <ipaaca/ipaaca.pb.h>
#include <set>
namespace ipaaca {
typedef uint32_t revision_t;
/// Type of the IU event. Realized as an integer to enable bit masks for filters.
typedef uint32_t IUEventType;
#define IU_ADDED 1
#define IU_COMMITTED 2
#define IU_DELETED 4
#define IU_RETRACTED 8
#define IU_UPDATED 16
#define IU_LINKSUPDATED 32
#define IU_MESSAGE 64
/// Bit mask for receiving all events
#define IU_ALL_EVENTS 127
/// Convert an int event type to a human-readable string
IPAACA_HEADER_EXPORT inline std::string iu_event_type_to_str(IUEventType type)
{
switch(type) {
case IU_ADDED: return "ADDED";
case IU_COMMITTED: return "COMMITTED";
case IU_DELETED: return "DELETED";
case IU_RETRACTED: return "RETRACTED";
case IU_UPDATED: return "UPDATED";
case IU_LINKSUPDATED: return "LINKSUPDATED";
case IU_MESSAGE: return "MESSAGE";
default: return "(NOT A KNOWN SINGLE IU EVENT TYPE)";
}
}
/// IU access mode: PUSH means that updates are broadcast; REMOTE means that reads are RPC calls; MESSAGE means a fire-and-forget message
IPAACA_HEADER_EXPORT enum IUAccessMode {
IU_ACCESS_PUSH,
IU_ACCESS_REMOTE,
IU_ACCESS_MESSAGE
};
class PayloadEntryProxy;
class Payload;
class IUInterface;
class IU;
class Message;
class RemotePushIU;
class IULinkUpdate;
class IUPayloadUpdate;
class IUStore;
class FrozenIUStore;
class Buffer;
class InputBuffer;
class OutputBuffer;
//class InputBufferRsbAdaptor;
//class OutputBufferRsbAdaptor;
class CallbackIUPayloadUpdate;
class CallbackIULinkUpdate;
class CallbackIUCommission;
class CallbackIURetraction;
class IUConverter;
class MessageConverter;
class IUPayloadUpdateConverter;
class IULinkUpdateConverter;
class IntConverter;
/// generate a UUID as an ASCII string
IPAACA_HEADER_EXPORT std::string generate_uuid_string();
/// store for (local) IUs. TODO Stores need to be unified more
IPAACA_HEADER_EXPORT class IUStore: public std::map<std::string, boost::shared_ptr<IU> >
{
};
/// store for RemotePushIUs. TODO Stores need to be unified more
IPAACA_HEADER_EXPORT class RemotePushIUStore: public std::map<std::string, boost::shared_ptr<RemotePushIU> > // TODO genericize to all remote IU types
{
};
IPAACA_HEADER_EXPORT class Exception: public std::exception//{{{
{
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _description;
public:
IPAACA_HEADER_EXPORT inline Exception(const std::string& description=""): _description(description) { }
IPAACA_HEADER_EXPORT inline ~Exception() throw() { }
IPAACA_HEADER_EXPORT const char* what() const throw() {
return _description.c_str();
}
};//}}}
IPAACA_HEADER_EXPORT class Abort: public std::exception//{{{
{
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _description;
public:
IPAACA_HEADER_EXPORT inline Abort(const std::string& description=""): _description(description) { }
IPAACA_HEADER_EXPORT inline ~Abort() throw() { }
IPAACA_HEADER_EXPORT const char* what() const throw() {
return _description.c_str();
}
};//}}}
/// a reentrant lock/mutex
#ifdef WIN32
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/thread.hpp>
IPAACA_HEADER_EXPORT class Lock
{
protected:
IPAACA_MEMBER_VAR_EXPORT boost::recursive_mutex _mutex;
public:
IPAACA_HEADER_EXPORT inline Lock() {
}
IPAACA_HEADER_EXPORT inline ~Lock() {
}
IPAACA_HEADER_EXPORT inline void lock() {
_mutex.lock();
}
IPAACA_HEADER_EXPORT inline void unlock() {
_mutex.unlock();
}
};
#if _WIN32 || _WIN64
#include <rpc.h>
#else
#include <pthread.h>
IPAACA_HEADER_EXPORT class Lock
{
protected:
IPAACA_MEMBER_VAR_EXPORT pthread_mutexattr_t _attrs;
IPAACA_MEMBER_VAR_EXPORT pthread_mutex_t _mutex;
public:
IPAACA_HEADER_EXPORT inline Lock() {
pthread_mutexattr_init(&_attrs);
pthread_mutexattr_settype(&_attrs, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&_mutex, &_attrs);
}
IPAACA_HEADER_EXPORT inline ~Lock() {
pthread_mutex_destroy(&_mutex);
pthread_mutexattr_destroy(&_attrs);
}
IPAACA_HEADER_EXPORT inline void lock() {
pthread_mutex_lock(&_mutex);
}
IPAACA_HEADER_EXPORT inline void unlock() {
pthread_mutex_unlock(&_mutex);
}
};
#include <uuid/uuid.h>
#include <glob.h>
#endif
/// Stack-based lock holder. Create in a new stack frame
/// (i.e. {}-block) and it will obtain the lock and
/// auto-release in on exiting the stack frame.
IPAACA_HEADER_EXPORT class Locker
{
protected:
IPAACA_MEMBER_VAR_EXPORT Lock* _lock;
private:
IPAACA_HEADER_EXPORT inline Locker(): _lock(NULL) { } // not available
public:
IPAACA_HEADER_EXPORT inline Locker(Lock& lock): _lock(&lock) {
//std::cout << "-- Locker: lock" << std::endl;
_lock->lock();
}
IPAACA_HEADER_EXPORT inline ~Locker() {
//std::cout << "-- Locker: unlock" << std::endl;
_lock->unlock();
}
};
#ifndef WIN32
IPAACA_HEADER_EXPORT class PthreadMutexLocker
{
protected:
IPAACA_MEMBER_VAR_EXPORT pthread_mutex_t* _lock;
private:
IPAACA_HEADER_EXPORT inline PthreadMutexLocker(): _lock(NULL) { } // not available
public:
IPAACA_HEADER_EXPORT inline PthreadMutexLocker(pthread_mutex_t* lock): _lock(lock) {
if (!lock) throw Exception("PthreadMutexLocker got a NULL mutex!");
pthread_mutex_lock(_lock);
}
IPAACA_HEADER_EXPORT inline ~PthreadMutexLocker() {
pthread_mutex_unlock(_lock);
}
};
#endif
typedef std::set<std::string> LinkSet;
typedef std::map<std::string, LinkSet> LinkMap;
IPAACA_HEADER_EXPORT class SmartLinkMap {
friend std::ostream& operator<<(std::ostream& os, const SmartLinkMap& obj);
friend class IUInterface;
friend class IU;
friend class IUConverter;
friend class MessageConverter;
public:
IPAACA_HEADER_EXPORT const LinkSet& get_links(const std::string& key);
IPAACA_HEADER_EXPORT const LinkMap& get_all_links();
protected:
IPAACA_MEMBER_VAR_EXPORT LinkMap _links;
IPAACA_MEMBER_VAR_EXPORT static LinkSet empty_link_set;
IPAACA_HEADER_EXPORT void _add_and_remove_links(const LinkMap& add, const LinkMap& remove);
IPAACA_HEADER_EXPORT void _replace_links(const LinkMap& links);
};
IPAACA_MEMBER_VAR_EXPORT const LinkSet EMPTY_LINK_SET;
//const std::set<std::string> EMPTY_LINK_SET;
//typedef boost::function<void (const std::string&, bool, IUEventType, const std::string&)> IUEventHandlerFunction;
IPAACA_HEADER_EXPORT typedef boost::function<void (boost::shared_ptr<IUInterface>, IUEventType, bool)> IUEventHandlerFunction;
IPAACA_HEADER_EXPORT class IUEventHandler {
protected:
IPAACA_MEMBER_VAR_EXPORT IUEventHandlerFunction _function;
IPAACA_MEMBER_VAR_EXPORT IUEventType _event_mask;
IPAACA_MEMBER_VAR_EXPORT bool _for_all_categories;
IPAACA_MEMBER_VAR_EXPORT std::set<std::string> _categories;
protected:
IPAACA_HEADER_EXPORT inline bool _condition_met(IUEventType event_type, const std::string& category)
{
return ((_event_mask&event_type)!=0) && (_for_all_categories || (_categories.count(category)>0));
}
public:
IPAACA_HEADER_EXPORT IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::string& category);
IPAACA_HEADER_EXPORT IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories);
//void call(Buffer* buffer, const std::string& uid, bool local, IUEventType event_type, const std::string& category);
IPAACA_HEADER_EXPORT void call(Buffer* buffer, boost::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category);
typedef boost::shared_ptr<IUEventHandler> ptr;
};
IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Buffer> {//{{{
friend class IU;
friend class RemotePushIU;
friend class CallbackIUPayloadUpdate;
friend class CallbackIULinkUpdate;
friend class CallbackIUCommission;
protected:
//Lock _handler_lock;
IPAACA_MEMBER_VAR_EXPORT std::string _uuid;
IPAACA_MEMBER_VAR_EXPORT std::string _basename;
IPAACA_MEMBER_VAR_EXPORT std::string _unique_name;
IPAACA_MEMBER_VAR_EXPORT std::string _id_prefix;
IPAACA_MEMBER_VAR_EXPORT std::vector<IUEventHandler::ptr> _event_handlers;
protected:
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _send_iu_link_update(IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name="undef") = 0;
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _send_iu_payload_update(IUInterface* iu, bool is_delta, revision_t revision, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="undef") = 0;
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name="undef") = 0;
IPAACA_HEADER_EXPORT void _allocate_unique_name(const std::string& basename, const std::string& function);
IPAACA_HEADER_EXPORT inline Buffer(const std::string& basename, const std::string& function) {
_allocate_unique_name(basename, function);
}
IPAACA_HEADER_EXPORT void call_iu_event_handlers(boost::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category);
public:
IPAACA_HEADER_EXPORT virtual inline ~Buffer() { }
IPAACA_HEADER_EXPORT inline const std::string& unique_name() { return _unique_name; }
IPAACA_HEADER_EXPORT void register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories);
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;
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual std::set<boost::shared_ptr<IUInterface> > get_ius() = 0;
};
//}}}
IPAACA_HEADER_EXPORT class OutputBuffer: public Buffer { //, public boost::enable_shared_from_this<OutputBuffer> {//{{{
friend class IU;
friend class RemotePushIU;
friend class OutputBufferRsbAdaptor;
protected:
protected:
//OutputBufferRsbAdaptor _rsb;
IPAACA_MEMBER_VAR_EXPORT IUStore _iu_store;
IPAACA_MEMBER_VAR_EXPORT Lock _iu_id_counter_lock;
#ifdef IPAACA_EXPOSE_FULL_RSB_API
protected:
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, rsb::Informer<rsb::AnyType>::Ptr> _informer_store;
IPAACA_MEMBER_VAR_EXPORT rsb::patterns::ServerPtr _server;
IPAACA_HEADER_EXPORT rsb::Informer<rsb::AnyType>::Ptr _get_informer(const std::string& category);
#endif
protected:
// informing functions
IPAACA_HEADER_EXPORT void _send_iu_link_update(IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name="undef");
IPAACA_HEADER_EXPORT void _send_iu_payload_update(IUInterface* iu, bool is_delta, revision_t revision, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="undef");
IPAACA_HEADER_EXPORT void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name);
// remote access functions
// _remote_update_links(IULinkUpdate)
// _remote_update_payload(IUPayloadUpdate)
// _remote_commit(protobuf::IUCommission)
IPAACA_HEADER_EXPORT void _publish_iu(boost::shared_ptr<IU> iu);
IPAACA_HEADER_EXPORT void _retract_iu(boost::shared_ptr<IU> iu);
protected:
IPAACA_HEADER_EXPORT OutputBuffer(const std::string& basename);
IPAACA_HEADER_EXPORT void _initialize_server();
public:
IPAACA_HEADER_EXPORT static boost::shared_ptr<OutputBuffer> create(const std::string& basename);
IPAACA_HEADER_EXPORT ~OutputBuffer() {
IPAACA_IMPLEMENT_ME
}
IPAACA_HEADER_EXPORT void add(boost::shared_ptr<IU> iu);
IPAACA_HEADER_EXPORT boost::shared_ptr<IU> remove(const std::string& iu_uid);
IPAACA_HEADER_EXPORT boost::shared_ptr<IU> remove(boost::shared_ptr<IU> iu);
IPAACA_HEADER_EXPORT boost::shared_ptr<IUInterface> get(const std::string& iu_uid);
IPAACA_HEADER_EXPORT std::set<boost::shared_ptr<IUInterface> > get_ius();
typedef boost::shared_ptr<OutputBuffer> ptr;
};
//}}}
IPAACA_HEADER_EXPORT class InputBuffer: public Buffer { //, public boost::enable_shared_from_this<InputBuffer> {//{{{
friend class IU;
friend class RemotePushIU;
friend class InputBufferRsbAdaptor;
//InputBufferRsbAdaptor _rsb;
#ifdef IPAACA_EXPOSE_FULL_RSB_API
protected:
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, rsb::ListenerPtr> _listener_store;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, rsb::patterns::RemoteServerPtr> _remote_server_store;
IPAACA_MEMBER_VAR_EXPORT RemotePushIUStore _iu_store; // TODO genericize
IPAACA_HEADER_EXPORT rsb::patterns::RemoteServerPtr _get_remote_server(const std::string& unique_server_name);
IPAACA_HEADER_EXPORT rsb::ListenerPtr _create_category_listener_if_needed(const std::string& category);
IPAACA_HEADER_EXPORT void _handle_iu_events(rsb::EventPtr event);
#endif
protected:
IPAACA_HEADER_EXPORT inline void _send_iu_link_update(IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name="undef")
{
IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_link_update() should never be invoked")
}
IPAACA_HEADER_EXPORT inline void _send_iu_payload_update(IUInterface* iu, bool is_delta, revision_t revision, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="undef")
{
IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_payload_update() should never be invoked")
}
IPAACA_HEADER_EXPORT inline void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name="undef")
{
IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_commission() should never be invoked")
}
protected:
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);
IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::string& category_interest1);
IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2);
IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3);
IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3, const std::string& category_interest4);
public:
IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::set<std::string>& category_interests);
IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::vector<std::string>& category_interests);
IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1);
IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2);
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);
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
}
IPAACA_HEADER_EXPORT boost::shared_ptr<IUInterface> get(const std::string& iu_uid);
IPAACA_HEADER_EXPORT std::set<boost::shared_ptr<IUInterface> > get_ius();
typedef boost::shared_ptr<InputBuffer> ptr;
};
//}}}
IPAACA_HEADER_EXPORT class IUPayloadUpdate {//{{{
public:
IPAACA_MEMBER_VAR_EXPORT std::string uid;
IPAACA_MEMBER_VAR_EXPORT revision_t revision;
IPAACA_MEMBER_VAR_EXPORT std::string writer_name;
IPAACA_MEMBER_VAR_EXPORT bool is_delta;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, std::string> new_items;
IPAACA_MEMBER_VAR_EXPORT std::vector<std::string> keys_to_remove;
friend std::ostream& operator<<(std::ostream& os, const IUPayloadUpdate& obj);
typedef boost::shared_ptr<IUPayloadUpdate> ptr;
};//}}}
IPAACA_HEADER_EXPORT class IULinkUpdate {//{{{
public:
IPAACA_MEMBER_VAR_EXPORT std::string uid;
IPAACA_MEMBER_VAR_EXPORT revision_t revision;
IPAACA_MEMBER_VAR_EXPORT std::string writer_name;
IPAACA_MEMBER_VAR_EXPORT bool is_delta;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, std::set<std::string> > new_links;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, std::set<std::string> > links_to_remove;
friend std::ostream& operator<<(std::ostream& os, const IULinkUpdate& obj);
typedef boost::shared_ptr<IULinkUpdate> ptr;
};//}}}
IPAACA_HEADER_EXPORT class Initializer
{
public:
IPAACA_HEADER_EXPORT static void initialize_ipaaca_rsb_if_needed();
IPAACA_HEADER_EXPORT static void initialize_updated_default_config();
IPAACA_HEADER_EXPORT static bool initialized();
IPAACA_HEADER_EXPORT static void dump_current_default_config();
protected:
IPAACA_MEMBER_VAR_EXPORT static bool _initialized;
};
IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
{
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 inline std::string to_str() { return operator std::string(); }
//inline long to_int() { return operator long(); }
IPAACA_HEADER_EXPORT inline long to_long() { return operator long(); }
IPAACA_HEADER_EXPORT inline double to_float() { return operator double(); }
IPAACA_HEADER_EXPORT inline bool to_bool() { return operator bool(); }
};//}}}
IPAACA_HEADER_EXPORT class Payload//{{{
{
friend std::ostream& operator<<(std::ostream& os, const Payload& obj);
friend class IUInterface;
friend class IU;
friend class Message;
friend class RemotePushIU;
friend class RemoteMessage;
friend class IUConverter;
friend class MessageConverter;
friend class CallbackIUPayloadUpdate;
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _owner_name;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, std::string> _store;
IPAACA_MEMBER_VAR_EXPORT boost::weak_ptr<IUInterface> _iu;
protected:
IPAACA_HEADER_EXPORT void initialize(boost::shared_ptr<IUInterface> iu);
IPAACA_HEADER_EXPORT inline void _set_owner_name(const std::string& name) { _owner_name = name; }
IPAACA_HEADER_EXPORT void _remotely_enforced_wipe();
IPAACA_HEADER_EXPORT void _remotely_enforced_delitem(const std::string& k);
IPAACA_HEADER_EXPORT void _remotely_enforced_setitem(const std::string& k, const std::string& v);
IPAACA_HEADER_EXPORT void _internal_replace_all(const std::map<std::string, std::string>& new_contents, const std::string& writer_name="");
IPAACA_HEADER_EXPORT void _internal_merge(const std::map<std::string, std::string>& contents_to_merge, const std::string& writer_name="");
IPAACA_HEADER_EXPORT void _internal_set(const std::string& k, const std::string& v, const std::string& writer_name="");
IPAACA_HEADER_EXPORT void _internal_remove(const std::string& k, const std::string& writer_name="");
public:
IPAACA_HEADER_EXPORT inline const std::string& owner_name() { return _owner_name; }
// access
IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const std::string& key);
IPAACA_HEADER_EXPORT operator std::map<std::string, std::string>();
IPAACA_HEADER_EXPORT inline void set(const std::map<std::string, std::string>& all_elems) { _internal_replace_all(all_elems); }
IPAACA_HEADER_EXPORT inline void set(const std::string& k, const std::string& v) { _internal_set(k, v); }
IPAACA_HEADER_EXPORT inline void merge(const std::map<std::string, std::string>& elems_to_merge) { _internal_merge(elems_to_merge); }
IPAACA_HEADER_EXPORT inline void remove(const std::string& k) { _internal_remove(k); }
IPAACA_HEADER_EXPORT std::string get(const std::string& k);
typedef boost::shared_ptr<Payload> ptr;
};//}}}
IPAACA_HEADER_EXPORT class IUInterface {//{{{
friend class IUConverter;
friend class MessageConverter;
friend std::ostream& operator<<(std::ostream& os, const IUInterface& obj);
protected:
IPAACA_HEADER_EXPORT IUInterface();
public:
IPAACA_HEADER_EXPORT inline virtual ~IUInterface() { }
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _uid;
IPAACA_MEMBER_VAR_EXPORT revision_t _revision;
IPAACA_MEMBER_VAR_EXPORT std::string _category;
IPAACA_MEMBER_VAR_EXPORT std::string _payload_type; // default is "MAP"
IPAACA_MEMBER_VAR_EXPORT std::string _owner_name;
IPAACA_MEMBER_VAR_EXPORT bool _committed;
IPAACA_MEMBER_VAR_EXPORT bool _retracted;
IPAACA_MEMBER_VAR_EXPORT IUAccessMode _access_mode;
IPAACA_MEMBER_VAR_EXPORT bool _read_only;
//boost::shared_ptr<Buffer> _buffer;
IPAACA_MEMBER_VAR_EXPORT Buffer* _buffer;
IPAACA_MEMBER_VAR_EXPORT SmartLinkMap _links;
protected:
friend class Payload;
// Internal functions that perform the update logic,
// e.g. sending a notification across the network
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) = 0;
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name) = 0;
//void _set_buffer(boost::shared_ptr<Buffer> buffer);
IPAACA_HEADER_EXPORT void _associate_with_buffer(Buffer* buffer);
IPAACA_HEADER_EXPORT void _set_buffer(Buffer* buffer);
IPAACA_HEADER_EXPORT void _set_uid(const std::string& uid);
IPAACA_HEADER_EXPORT void _set_owner_name(const std::string& owner_name);
protected:
// internal functions that do not emit update events
IPAACA_HEADER_EXPORT inline void _add_and_remove_links(const LinkMap& add, const LinkMap& remove) { _links._add_and_remove_links(add, remove); }
IPAACA_HEADER_EXPORT inline void _replace_links(const LinkMap& links) { _links._replace_links(links); }
public:
IPAACA_HEADER_EXPORT inline bool is_published() { return (_buffer != 0); }
IPAACA_HEADER_EXPORT inline const std::string& uid() const { return _uid; }
IPAACA_HEADER_EXPORT inline revision_t revision() const { return _revision; }
IPAACA_HEADER_EXPORT inline const std::string& category() const { return _category; }
IPAACA_HEADER_EXPORT inline const std::string& payload_type() const { return _payload_type; }
IPAACA_HEADER_EXPORT inline const std::string& owner_name() const { return _owner_name; }
IPAACA_HEADER_EXPORT inline bool committed() const { return _committed; }
IPAACA_HEADER_EXPORT inline IUAccessMode access_mode() const { return _access_mode; }
IPAACA_HEADER_EXPORT inline bool read_only() const { return _read_only; }
//inline boost::shared_ptr<Buffer> buffer() { return _buffer; }
IPAACA_HEADER_EXPORT inline Buffer* buffer() const { return _buffer; }
IPAACA_HEADER_EXPORT inline const LinkSet& get_links(std::string type) { return _links.get_links(type); }
IPAACA_HEADER_EXPORT inline const LinkMap& get_all_links() { return _links.get_all_links(); }
// Payload
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual Payload& payload() = 0;
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual const Payload& const_payload() const = 0;
// setters
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void commit() = 0;
// functions to modify and update links:
IPAACA_HEADER_EXPORT void add_links(const std::string& type, const LinkSet& targets, const std::string& writer_name = "");
IPAACA_HEADER_EXPORT void remove_links(const std::string& type, const LinkSet& targets, const std::string& writer_name = "");
IPAACA_HEADER_EXPORT void modify_links(const LinkMap& add, const LinkMap& remove, const std::string& writer_name = "");
IPAACA_HEADER_EXPORT void set_links(const LinkMap& links, const std::string& writer_name = "");
// (with cpp specific convenience functions:)
IPAACA_HEADER_EXPORT void add_link(const std::string& type, const std::string& target, const std::string& writer_name = "");
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;
};//}}}
IPAACA_HEADER_EXPORT class IU: public IUInterface {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class CallbackIUPayloadUpdate;
friend class CallbackIULinkUpdate;
friend class CallbackIUCommission;
public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected:
IPAACA_MEMBER_VAR_EXPORT Lock _revision_lock;
protected:
IPAACA_HEADER_EXPORT inline void _increase_revision_number() { _revision++; }
IPAACA_HEADER_EXPORT IU(const std::string& category, IUAccessMode access_mode=IU_ACCESS_PUSH, bool read_only=false, const std::string& payload_type="MAP" );
public:
IPAACA_HEADER_EXPORT inline ~IU() {
//IPAACA_IMPLEMENT_ME
}
IPAACA_HEADER_EXPORT static boost::shared_ptr<IU> create(const std::string& category, IUAccessMode access_mode=IU_ACCESS_PUSH, bool read_only=false, const std::string& payload_type="MAP" );
IPAACA_HEADER_EXPORT inline Payload& payload() { return _payload; }
IPAACA_HEADER_EXPORT inline const Payload& const_payload() const { return _payload; }
IPAACA_HEADER_EXPORT void commit();
protected:
IPAACA_HEADER_EXPORT virtual void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "");
IPAACA_HEADER_EXPORT virtual void _modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "");
protected:
IPAACA_HEADER_EXPORT virtual void _internal_commit(const std::string& writer_name = "");
public:
typedef boost::shared_ptr<IU> ptr;
};//}}}
IPAACA_HEADER_EXPORT class Message: public IU {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class CallbackIUPayloadUpdate;
friend class CallbackIULinkUpdate;
friend class CallbackIUCommission;
protected:
IPAACA_HEADER_EXPORT Message(const std::string& category, IUAccessMode access_mode=IU_ACCESS_MESSAGE, bool read_only=true, const std::string& payload_type="MAP" );
public:
IPAACA_HEADER_EXPORT inline ~Message() {
//IPAACA_IMPLEMENT_ME
}
IPAACA_HEADER_EXPORT static boost::shared_ptr<Message> create(const std::string& category, IUAccessMode access_mode=IU_ACCESS_MESSAGE, bool read_only=true, const std::string& payload_type="MAP" );
protected:
IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "");
IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "");
protected:
IPAACA_HEADER_EXPORT void _internal_commit(const std::string& writer_name = "");
public:
typedef boost::shared_ptr<Message> ptr;
};//}}}
IPAACA_HEADER_EXPORT class RemotePushIU: public IUInterface {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class IUConverter;
friend class MessageConverter;
public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected:
IPAACA_HEADER_EXPORT RemotePushIU();
IPAACA_HEADER_EXPORT static boost::shared_ptr<RemotePushIU> create();
public:
IPAACA_HEADER_EXPORT inline ~RemotePushIU() {
//IPAACA_IMPLEMENT_ME
}
IPAACA_HEADER_EXPORT inline Payload& payload() { return _payload; }
IPAACA_HEADER_EXPORT inline const Payload& const_payload() const { return _payload; }
IPAACA_HEADER_EXPORT void commit();
protected:
IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "");
IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "");
protected:
IPAACA_HEADER_EXPORT void _apply_update(IUPayloadUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_commission();
IPAACA_HEADER_EXPORT void _apply_retraction();
typedef boost::shared_ptr<RemotePushIU> ptr;
};//}}}
IPAACA_HEADER_EXPORT class RemoteMessage: public IUInterface {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class IUConverter;
friend class MessageConverter;
public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected:
IPAACA_HEADER_EXPORT RemoteMessage();
IPAACA_HEADER_EXPORT static boost::shared_ptr<RemoteMessage> create();
public:
IPAACA_HEADER_EXPORT inline ~RemoteMessage() {
//IPAACA_IMPLEMENT_ME
}
IPAACA_HEADER_EXPORT inline Payload& payload() { return _payload; }
IPAACA_HEADER_EXPORT inline const Payload& const_payload() const { return _payload; }
IPAACA_HEADER_EXPORT void commit();
protected:
IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "");
IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "");
protected:
IPAACA_HEADER_EXPORT void _apply_update(IUPayloadUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_commission();
IPAACA_HEADER_EXPORT void _apply_retraction();
typedef boost::shared_ptr<RemoteMessage> ptr;
};//}}}
IPAACA_HEADER_EXPORT class IUNotFoundError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUNotFoundError() throw() { }
IPAACA_HEADER_EXPORT inline IUNotFoundError() { //boost::shared_ptr<IU> iu) {
_description = "IUNotFoundError";
}
};//}}}
IPAACA_HEADER_EXPORT class IUPublishedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUPublishedError() throw() { }
IPAACA_HEADER_EXPORT inline IUPublishedError() { //boost::shared_ptr<IU> iu) {
_description = "IUPublishedError";
}
};//}}}
IPAACA_HEADER_EXPORT class IUCommittedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUCommittedError() throw() { }
IPAACA_HEADER_EXPORT inline IUCommittedError() { //boost::shared_ptr<IU> iu) {
_description = "IUCommittedError";
}
};//}}}
IPAACA_HEADER_EXPORT class IUUpdateFailedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUUpdateFailedError() throw() { }
IPAACA_HEADER_EXPORT inline IUUpdateFailedError() { //boost::shared_ptr<IU> iu) {
_description = "IUUpdateFailedError";
}
};//}}}
IPAACA_HEADER_EXPORT class IUReadOnlyError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUReadOnlyError() throw() { }
IPAACA_HEADER_EXPORT inline IUReadOnlyError() { //boost::shared_ptr<IU> iu) {
_description = "IUReadOnlyError";
}
};//}}}
IPAACA_HEADER_EXPORT class IUAlreadyInABufferError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUAlreadyInABufferError() throw() { }
IPAACA_HEADER_EXPORT inline IUAlreadyInABufferError() { //boost::shared_ptr<IU> iu) {
_description = "IUAlreadyInABufferError";
}
};//}}}
IPAACA_HEADER_EXPORT class IUAlreadyHasAnUIDError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUAlreadyHasAnUIDError() throw() { }
IPAACA_HEADER_EXPORT inline IUAlreadyHasAnUIDError() { //boost::shared_ptr<IU> iu) {
_description = "IUAlreadyHasAnUIDError";
}
};//}}}
IPAACA_HEADER_EXPORT class IUAlreadyHasAnOwnerNameError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUAlreadyHasAnOwnerNameError() throw() { }
IPAACA_HEADER_EXPORT inline IUAlreadyHasAnOwnerNameError() { //boost::shared_ptr<IU> iu) {
_description = "IUAlreadyHasAnOwnerNameError";
}
};//}}}
IPAACA_HEADER_EXPORT class UUIDGenerationError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~UUIDGenerationError() throw() { }
IPAACA_HEADER_EXPORT inline UUIDGenerationError() { //boost::shared_ptr<IU> iu) {
_description = "UUIDGenerationError";
}
};//}}}
IPAACA_HEADER_EXPORT class NotImplementedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~NotImplementedError() throw() { }
IPAACA_HEADER_EXPORT inline NotImplementedError() { //boost::shared_ptr<IU> iu) {
_description = "NotImplementedError";
}
};//}}}
#ifdef IPAACA_EXPOSE_FULL_RSB_API
IPAACA_HEADER_EXPORT class CallbackIUPayloadUpdate: public rsb::patterns::Server::Callback<IUPayloadUpdate, int> {//{{{
protected:
IPAACA_MEMBER_VAR_EXPORT Buffer* _buffer;
public:
IPAACA_HEADER_EXPORT CallbackIUPayloadUpdate(Buffer* buffer);
IPAACA_HEADER_EXPORT boost::shared_ptr<int> call(const std::string& methodName, boost::shared_ptr<IUPayloadUpdate> update);
};//}}}
IPAACA_HEADER_EXPORT class CallbackIULinkUpdate: public rsb::patterns::Server::Callback<IULinkUpdate, int> {//{{{
protected:
IPAACA_MEMBER_VAR_EXPORT Buffer* _buffer;
public:
IPAACA_HEADER_EXPORT CallbackIULinkUpdate(Buffer* buffer);
public:
IPAACA_HEADER_EXPORT boost::shared_ptr<int> call(const std::string& methodName, boost::shared_ptr<IULinkUpdate> update);
};//}}}
IPAACA_HEADER_EXPORT class CallbackIUCommission: public rsb::patterns::Server::Callback<protobuf::IUCommission, int> {//{{{
protected:
IPAACA_MEMBER_VAR_EXPORT Buffer* _buffer;
public:
IPAACA_HEADER_EXPORT CallbackIUCommission(Buffer* buffer);
public:
IPAACA_HEADER_EXPORT boost::shared_ptr<int> call(const std::string& methodName, boost::shared_ptr<protobuf::IUCommission> update);
};//}}}
IPAACA_HEADER_EXPORT class CallbackIURetraction: public rsb::patterns::Server::Callback<protobuf::IURetraction, int> {//{{{
protected:
IPAACA_MEMBER_VAR_EXPORT Buffer* _buffer;
public:
IPAACA_HEADER_EXPORT CallbackIURetraction(Buffer* buffer);
public:
IPAACA_HEADER_EXPORT boost::shared_ptr<int> call(const std::string& methodName, boost::shared_ptr<protobuf::IURetraction> update);
};//}}}
IPAACA_HEADER_EXPORT class IUConverter: public rsb::converter::Converter<std::string> {//{{{
public:
IPAACA_HEADER_EXPORT IUConverter();
IPAACA_HEADER_EXPORT std::string serialize(const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT rsb::AnnotatedData deserialize(const std::string& wireSchema, const std::string& wire);
};//}}}
IPAACA_HEADER_EXPORT class MessageConverter: public rsb::converter::Converter<std::string> {//{{{
public:
IPAACA_HEADER_EXPORT MessageConverter();
IPAACA_HEADER_EXPORT std::string serialize(const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT rsb::AnnotatedData deserialize(const std::string& wireSchema, const std::string& wire);
};//}}}
IPAACA_HEADER_EXPORT class IUPayloadUpdateConverter: public rsb::converter::Converter<std::string> {//{{{
public:
IPAACA_HEADER_EXPORT IUPayloadUpdateConverter();
IPAACA_HEADER_EXPORT std::string serialize(const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT rsb::AnnotatedData deserialize(const std::string& wireSchema, const std::string& wire);
};//}}}
IPAACA_HEADER_EXPORT class IULinkUpdateConverter: public rsb::converter::Converter<std::string> {//{{{
public:
IPAACA_HEADER_EXPORT IULinkUpdateConverter();
IPAACA_HEADER_EXPORT std::string serialize(const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT rsb::AnnotatedData deserialize(const std::string& wireSchema, const std::string& wire);
};//}}}
IPAACA_HEADER_EXPORT class IntConverter: public rsb::converter::Converter<std::string> {//{{{
public:
IPAACA_HEADER_EXPORT IntConverter();
IPAACA_HEADER_EXPORT std::string serialize(const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT rsb::AnnotatedData deserialize(const std::string& wireSchema, const std::string& wire);
};//}}}
#ifndef Q_MOC_RUN
#include <memory>
#include <functional>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>
#endif
// additional misc classes ( Command line options )//{{{
IPAACA_HEADER_EXPORT class CommandLineOptions {
public:
IPAACA_HEADER_EXPORT inline CommandLineOptions() { }
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, std::string> param_opts;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, bool> param_set;
public:
IPAACA_HEADER_EXPORT void set_option(const std::string& name, bool expect, const char* optarg);
IPAACA_HEADER_EXPORT std::string get_param(const std::string& o);
IPAACA_HEADER_EXPORT bool is_set(const std::string& o);
IPAACA_HEADER_EXPORT void dump();
typedef boost::shared_ptr<CommandLineOptions> ptr;
};
#include <ipaaca/ipaaca.pb.h>
class CommandLineParser {
protected:
IPAACA_MEMBER_VAR_EXPORT std::map<char, std::string> longopt; // letter->name
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, char> shortopt; // letter->name
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, bool> options; // name / expect_param
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, std::string> defaults; // for opt params
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, int> set_flag; // for paramless opts
protected:
IPAACA_HEADER_EXPORT CommandLineParser();
public:
IPAACA_HEADER_EXPORT inline ~CommandLineParser() { }
IPAACA_HEADER_EXPORT static inline boost::shared_ptr<CommandLineParser> create() {
return boost::shared_ptr<CommandLineParser>(new CommandLineParser());
}
IPAACA_HEADER_EXPORT void initialize_parser_defaults();
IPAACA_HEADER_EXPORT void dump_options();
IPAACA_HEADER_EXPORT void add_option(const std::string& optname, char shortn, bool expect_param, const std::string& defaultv);
IPAACA_HEADER_EXPORT void ensure_defaults_in( CommandLineOptions::ptr clo );
IPAACA_HEADER_EXPORT CommandLineOptions::ptr parse(int argc, char* const* argv);
typedef boost::shared_ptr<CommandLineParser> ptr;
};
//}}}
#include <set>
#include <list>
#include <algorithm>
#include <utility>
#include <initializer_list>
// additional misc functions ( String splitting / joining )//{{{
IPAACA_HEADER_EXPORT std::string str_join(const std::set<std::string>& set,const std::string& sep);
IPAACA_HEADER_EXPORT std::string str_join(const std::vector<std::string>& vec,const std::string& sep);
IPAACA_HEADER_EXPORT void str_split_wipe(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters );
IPAACA_HEADER_EXPORT void str_split_append(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters );
//}}}
namespace ipaaca {
// (snippets) //{{{
/*
class IUEventFunctionHandler: public rsb::EventFunctionHandler {
protected:
Buffer* _buffer;
public:
inline IUEventFunctionHandler(Buffer* buffer, const EventFunction& function, const std::string& method="")
: EventFunctionHandler(function, method), _buffer(buffer) { }
};
*/
//}}}
#include <ipaaca/ipaaca-definitions.h>
#include <ipaaca/ipaaca-forwards.h>
#include <ipaaca/ipaaca-errors.h>
#include <ipaaca/ipaaca-initializer.h>
#include <ipaaca/ipaaca-locking.h>
#include <ipaaca/ipaaca-cmdline-parser.h>
#include <ipaaca/ipaaca-string-utils.h>
// Global static library variables (run-time default configuration)
// Actual initial values are set in ipaaca.cc
/// Default payload type for new IUs (defaults to "JSON")
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_default_payload_type;
/// Default channel for buffers (defaults to "default")
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_default_channel;
/// Current console log level (defaults to warning), one of: IPAACA_LOG_LEVEL_CRITICAL, IPAACA_LOG_LEVEL_ERROR, IPAACA_LOG_LEVEL_WARNING, IPAACA_LOG_LEVEL_INFO, IPAACA_LOG_LEVEL_DEBUG, IPAACA_LOG_LEVEL_NONE
IPAACA_MEMBER_VAR_EXPORT extern unsigned int __ipaaca_static_option_log_level;
/// RSB host to connect to (defaults to "" = do not set, use global config)
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_rsb_host;
/// RSB port to connect to (defaults to "" = do not set, use global config)
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_rsb_port;
/// RSB transport to use (defaults to "" = do not set, use global config)
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_rsb_transport;
/// Whether to run in server mode on 'socket' transport (defaults to "" = do not set, use global config)
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_rsb_socketserver;
IPAACA_MEMBER_VAR_EXPORT Lock& logger_lock();
#ifdef WIN32
#if _WIN32 || _WIN64
#define LOG_IPAACA_CONSOLE(msg) { ipaaca::Locker logging_locker(ipaaca::logger_lock()); std::time_t result = std::time(NULL); std::cout << "[LOG] " << std::asctime(std::localtime(&result)) << " : " << msg << std::endl; }
#else
// use normal gettimeofday() on POSIX
#define LOG_IPAACA_CONSOLE(msg) { ipaaca::Locker logging_locker(ipaaca::logger_lock()); timeval logging_tim; gettimeofday(&logging_tim, NULL); double logging_t1=logging_tim.tv_sec+(logging_tim.tv_usec/1000000.0); std::cout << "[LOG] " << std::setprecision(15) << logging_t1 << " : " << msg << std::endl; }
#endif
#if _WIN32 || _WIN64
#define IPAACA_SIMPLE_TIMER_BEGIN(N) ;
#define IPAACA_SIMPLE_TIMER_END(N, NAME) LOG_IPAACA_CONSOLE(NAME << " - time elapsed: Windows - IMPLEMENT ME")
#else
/// use IPAACA_SIMPLE_TIMER_BEGIN(mysymbol) to start time profiling at a line in code
/// Several blocks can be defined in the same stack frame if different symbols are chosen
#define IPAACA_SIMPLE_TIMER_BEGIN(N) struct timeval _ipaaca_timer_tvstart_ ## N; \
gettimeofday(&_ipaaca_timer_tvstart_ ## N, NULL);
/// use IPAACA_SIMPLE_TIMER_END(mysymbol, "message") to print time elapsed since correpsonding _BEGIN
#define IPAACA_SIMPLE_TIMER_END(N, NAME) struct timeval _ipaaca_timer_tvend_ ## N; \
gettimeofday(&_ipaaca_timer_tvend_ ## N, NULL); \
long _ipaaca_timer_usecs_ ## N = (_ipaaca_timer_tvend_ ## N.tv_sec*1000000 + _ipaaca_timer_tvend_ ## N.tv_usec) - (_ipaaca_timer_tvstart_ ## N.tv_sec*1000000 + _ipaaca_timer_tvstart_ ## N.tv_usec); \
LOG_IPAACA_CONSOLE(NAME << " - ̨́us elapsed: " << _ipaaca_timer_usecs_ ## N)
#endif
#include <ipaaca/ipaaca-config.h>
#include <ipaaca/ipaaca-converters.h>
#include <ipaaca/ipaaca-backend.h>
#include <ipaaca/ipaaca-payload.h>
#include <ipaaca/ipaaca-buffers.h>
#include <ipaaca/ipaaca-ius.h>
} // of namespace ipaaca
......
......@@ -3,8 +3,9 @@
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2013 Sociable Agents Group
* CITEC, Bielefeld University
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
......@@ -30,6 +31,17 @@
* Excellence Initiative.
*/
/**
* \file util/notifier.h
*
* \brief Header file for component notification (i.e. module-level introspection).
*
* Include this file in addition to ipaaca.h to use the functionality.
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __IPAACA_UTIL_NOTIFIER_H__
#define __IPAACA_UTIL_NOTIFIER_H__
......@@ -55,8 +67,8 @@ class ComponentNotifier {
ComponentNotifier(const std::string& componentName, const std::string& componentFunction, const std::set<std::string>& sendCategories, const std::set<std::string>& receiveCategories);
ComponentNotifier(const std::string& componentName, const std::string& componentFunction, const std::set<std::string>& sendCategories, const std::set<std::string>& receiveCategories, ipaaca::OutputBuffer::ptr out_buf, ipaaca::InputBuffer::ptr in_buf);
public:
static boost::shared_ptr<ComponentNotifier> create(const std::string& componentName, const std::string& componentFunction, const std::set<std::string>& sendCategories, const std::set<std::string>& receiveCategories);
static boost::shared_ptr<ComponentNotifier> create(const std::string& componentName, const std::string& componentFunction, const std::set<std::string>& sendCategories, const std::set<std::string>& receiveCategories, ipaaca::OutputBuffer::ptr out_buf, ipaaca::InputBuffer::ptr in_buf);
static std::shared_ptr<ComponentNotifier> create(const std::string& componentName, const std::string& componentFunction, const std::set<std::string>& sendCategories, const std::set<std::string>& receiveCategories);
static std::shared_ptr<ComponentNotifier> create(const std::string& componentName, const std::string& componentFunction, const std::set<std::string>& sendCategories, const std::set<std::string>& receiveCategories, ipaaca::OutputBuffer::ptr out_buf, ipaaca::InputBuffer::ptr in_buf);
public:
~ComponentNotifier();
protected:
......@@ -79,7 +91,7 @@ class ComponentNotifier {
std::string send_categories;
std::string recv_categories;
public:
typedef boost::shared_ptr<ComponentNotifier> ptr;
typedef std::shared_ptr<ComponentNotifier> ptr;
};
......
Copyright (C) 2011 Milo Yip
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
--
This software and license copied in January 2015 from
https://github.com/miloyip/rapidjson/
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ALLOCATORS_H_
#define RAPIDJSON_ALLOCATORS_H_
#include "rapidjson.h"
#include "internal/meta.h"
#include <memory>
#if RAPIDJSON_HAS_CXX11
#include <type_traits>
#endif
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Allocator
/*! \class rapidjson::Allocator
\brief Concept for allocating, resizing and freeing memory block.
Note that Malloc() and Realloc() are non-static but Free() is static.
So if an allocator need to support Free(), it needs to put its pointer in
the header of memory block.
\code
concept Allocator {
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
// Allocate a memory block.
// \param size of the memory block in bytes.
// \returns pointer to the memory block.
void* Malloc(size_t size);
// Resize a memory block.
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
// \param newSize the new size in bytes.
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
// Free a memory block.
// \param pointer to the memory block. Null pointer is permitted.
static void Free(void *ptr);
};
\endcode
*/
/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
\ingroup RAPIDJSON_CONFIG
\brief User-defined kDefaultChunkCapacity definition.
User can define this as any \c size that is a power of 2.
*/
#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
#endif
///////////////////////////////////////////////////////////////////////////////
// CrtAllocator
//! C-runtime library allocator.
/*! This class is just wrapper for standard C library memory routines.
\note implements Allocator concept
*/
class CrtAllocator {
public:
static const bool kNeedFree = true;
void* Malloc(size_t size) {
if (size) // behavior of malloc(0) is implementation defined.
return RAPIDJSON_MALLOC(size);
else
return NULL; // standardize to returning NULL.
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
(void)originalSize;
if (newSize == 0) {
RAPIDJSON_FREE(originalPtr);
return NULL;
}
return RAPIDJSON_REALLOC(originalPtr, newSize);
}
static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }
bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
return true;
}
bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
return false;
}
};
///////////////////////////////////////////////////////////////////////////////
// MemoryPoolAllocator
//! Default memory allocator used by the parser and DOM.
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
It does not free memory blocks. And Realloc() only allocate new memory.
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
User may also supply a buffer as the first chunk.
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
The user-buffer is not deallocated by this allocator.
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
\note implements Allocator concept
*/
template <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator {
//! Chunk header for perpending to each chunk.
/*! Chunks are stored as a singly linked list.
*/
struct ChunkHeader {
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
size_t size; //!< Current size of allocated memory in bytes.
ChunkHeader *next; //!< Next chunk in the linked list.
};
struct SharedData {
ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
BaseAllocator* ownBaseAllocator; //!< base allocator created by this object.
size_t refcount;
bool ownBuffer;
};
static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData));
static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader));
static inline ChunkHeader *GetChunkHead(SharedData *shared)
{
return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
}
static inline uint8_t *GetChunkBuffer(SharedData *shared)
{
return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER;
}
static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
public:
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy
//! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
explicit
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunk_capacity_(chunkSize),
baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0))
{
RAPIDJSON_ASSERT(baseAllocator_ != 0);
RAPIDJSON_ASSERT(shared_ != 0);
if (baseAllocator) {
shared_->ownBaseAllocator = 0;
}
else {
shared_->ownBaseAllocator = baseAllocator_;
}
shared_->chunkHead = GetChunkHead(shared_);
shared_->chunkHead->capacity = 0;
shared_->chunkHead->size = 0;
shared_->chunkHead->next = 0;
shared_->ownBuffer = true;
shared_->refcount = 1;
}
//! Constructor with user-supplied buffer.
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
The user buffer will not be deallocated when this allocator is destructed.
\param buffer User supplied buffer.
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunk_capacity_(chunkSize),
baseAllocator_(baseAllocator),
shared_(static_cast<SharedData*>(AlignBuffer(buffer, size)))
{
RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER);
shared_->chunkHead = GetChunkHead(shared_);
shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER;
shared_->chunkHead->size = 0;
shared_->chunkHead->next = 0;
shared_->ownBaseAllocator = 0;
shared_->ownBuffer = false;
shared_->refcount = 1;
}
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT :
chunk_capacity_(rhs.chunk_capacity_),
baseAllocator_(rhs.baseAllocator_),
shared_(rhs.shared_)
{
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
++shared_->refcount;
}
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
++rhs.shared_->refcount;
this->~MemoryPoolAllocator();
baseAllocator_ = rhs.baseAllocator_;
chunk_capacity_ = rhs.chunk_capacity_;
shared_ = rhs.shared_;
return *this;
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT :
chunk_capacity_(rhs.chunk_capacity_),
baseAllocator_(rhs.baseAllocator_),
shared_(rhs.shared_)
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
rhs.shared_ = 0;
}
MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
this->~MemoryPoolAllocator();
baseAllocator_ = rhs.baseAllocator_;
chunk_capacity_ = rhs.chunk_capacity_;
shared_ = rhs.shared_;
rhs.shared_ = 0;
return *this;
}
#endif
//! Destructor.
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
*/
~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT {
if (!shared_) {
// do nothing if moved
return;
}
if (shared_->refcount > 1) {
--shared_->refcount;
return;
}
Clear();
BaseAllocator *a = shared_->ownBaseAllocator;
if (shared_->ownBuffer) {
baseAllocator_->Free(shared_);
}
RAPIDJSON_DELETE(a);
}
//! Deallocates all memory chunks, excluding the first/user one.
void Clear() RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
for (;;) {
ChunkHeader* c = shared_->chunkHead;
if (!c->next) {
break;
}
shared_->chunkHead = c->next;
baseAllocator_->Free(c);
}
shared_->chunkHead->size = 0;
}
//! Computes the total capacity of allocated memory chunks.
/*! \return total capacity in bytes.
*/
size_t Capacity() const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
size_t capacity = 0;
for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
capacity += c->capacity;
return capacity;
}
//! Computes the memory blocks allocated.
/*! \return total used bytes.
*/
size_t Size() const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
size_t size = 0;
for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
size += c->size;
return size;
}
//! Whether the allocator is shared.
/*! \return true or false.
*/
bool Shared() const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
return shared_->refcount > 1;
}
//! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
if (!size)
return NULL;
size = RAPIDJSON_ALIGN(size);
if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity))
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
return NULL;
void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size;
shared_->chunkHead->size += size;
return buffer;
}
//! Resizes a memory block (concept Allocator)
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
if (originalPtr == 0)
return Malloc(newSize);
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
if (newSize == 0)
return NULL;
originalSize = RAPIDJSON_ALIGN(originalSize);
newSize = RAPIDJSON_ALIGN(newSize);
// Do not shrink if new size is smaller than original
if (originalSize >= newSize)
return originalPtr;
// Simply expand it if it is the last allocation and there is sufficient space
if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) {
size_t increment = static_cast<size_t>(newSize - originalSize);
if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) {
shared_->chunkHead->size += increment;
return originalPtr;
}
}
// Realloc process: allocate and copy memory, do not free original buffer.
if (void* newBuffer = Malloc(newSize)) {
if (originalSize)
std::memcpy(newBuffer, originalPtr, originalSize);
return newBuffer;
}
else
return NULL;
}
//! Frees a memory block (concept Allocator)
static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing
//! Compare (equality) with another MemoryPoolAllocator
bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
return shared_ == rhs.shared_;
}
//! Compare (inequality) with another MemoryPoolAllocator
bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
return !operator==(rhs);
}
private:
//! Creates a new chunk.
/*! \param capacity Capacity of the chunk in bytes.
\return true if success.
*/
bool AddChunk(size_t capacity) {
if (!baseAllocator_)
shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
if (ChunkHeader* chunk = static_cast<ChunkHeader*>(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) {
chunk->capacity = capacity;
chunk->size = 0;
chunk->next = shared_->chunkHead;
shared_->chunkHead = chunk;
return true;
}
else
return false;
}
static inline void* AlignBuffer(void* buf, size_t &size)
{
RAPIDJSON_NOEXCEPT_ASSERT(buf != 0);
const uintptr_t mask = sizeof(void*) - 1;
const uintptr_t ubuf = reinterpret_cast<uintptr_t>(buf);
if (RAPIDJSON_UNLIKELY(ubuf & mask)) {
const uintptr_t abuf = (ubuf + mask) & ~mask;
RAPIDJSON_ASSERT(size >= abuf - ubuf);
buf = reinterpret_cast<void*>(abuf);
size -= abuf - ubuf;
}
return buf;
}
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
SharedData *shared_; //!< The shared data of the allocator
};
namespace internal {
template<typename, typename = void>
struct IsRefCounted :
public FalseType
{ };
template<typename T>
struct IsRefCounted<T, typename internal::EnableIfCond<T::kRefCounted>::Type> :
public TrueType
{ };
}
template<typename T, typename A>
inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n)
{
RAPIDJSON_NOEXCEPT_ASSERT(old_n <= SIZE_MAX / sizeof(T) && new_n <= SIZE_MAX / sizeof(T));
return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
}
template<typename T, typename A>
inline T *Malloc(A& a, size_t n = 1)
{
return Realloc<T, A>(a, NULL, 0, n);
}
template<typename T, typename A>
inline void Free(A& a, T *p, size_t n = 1)
{
static_cast<void>(Realloc<T, A>(a, p, n, 0));
}
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited
#endif
template <typename T, typename BaseAllocator = CrtAllocator>
class StdAllocator :
public std::allocator<T>
{
typedef std::allocator<T> allocator_type;
#if RAPIDJSON_HAS_CXX11
typedef std::allocator_traits<allocator_type> traits_type;
#else
typedef allocator_type traits_type;
#endif
public:
typedef BaseAllocator BaseAllocatorType;
StdAllocator() RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_()
{ }
StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
template<typename U>
StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(std::move(rhs)),
baseAllocator_(std::move(rhs.baseAllocator_))
{ }
#endif
#if RAPIDJSON_HAS_CXX11
using propagate_on_container_move_assignment = std::true_type;
using propagate_on_container_swap = std::true_type;
#endif
/* implicit */
StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_(allocator)
{ }
~StdAllocator() RAPIDJSON_NOEXCEPT
{ }
template<typename U>
struct rebind {
typedef StdAllocator<U, BaseAllocator> other;
};
typedef typename traits_type::size_type size_type;
typedef typename traits_type::difference_type difference_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::pointer pointer;
typedef typename traits_type::const_pointer const_pointer;
#if RAPIDJSON_HAS_CXX11
typedef typename std::add_lvalue_reference<value_type>::type &reference;
typedef typename std::add_lvalue_reference<typename std::add_const<value_type>::type>::type &const_reference;
pointer address(reference r) const RAPIDJSON_NOEXCEPT
{
return std::addressof(r);
}
const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
{
return std::addressof(r);
}
size_type max_size() const RAPIDJSON_NOEXCEPT
{
return traits_type::max_size(*this);
}
template <typename ...Args>
void construct(pointer p, Args&&... args)
{
traits_type::construct(*this, p, std::forward<Args>(args)...);
}
void destroy(pointer p)
{
traits_type::destroy(*this, p);
}
#else // !RAPIDJSON_HAS_CXX11
typedef typename allocator_type::reference reference;
typedef typename allocator_type::const_reference const_reference;
pointer address(reference r) const RAPIDJSON_NOEXCEPT
{
return allocator_type::address(r);
}
const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
{
return allocator_type::address(r);
}
size_type max_size() const RAPIDJSON_NOEXCEPT
{
return allocator_type::max_size();
}
void construct(pointer p, const_reference r)
{
allocator_type::construct(p, r);
}
void destroy(pointer p)
{
allocator_type::destroy(p);
}
#endif // !RAPIDJSON_HAS_CXX11
template <typename U>
U* allocate(size_type n = 1, const void* = 0)
{
return RAPIDJSON_NAMESPACE::Malloc<U>(baseAllocator_, n);
}
template <typename U>
void deallocate(U* p, size_type n = 1)
{
RAPIDJSON_NAMESPACE::Free<U>(baseAllocator_, p, n);
}
pointer allocate(size_type n = 1, const void* = 0)
{
return allocate<value_type>(n);
}
void deallocate(pointer p, size_type n = 1)
{
deallocate<value_type>(p, n);
}
#if RAPIDJSON_HAS_CXX11
using is_always_equal = std::is_empty<BaseAllocator>;
#endif
template<typename U>
bool operator==(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
{
return baseAllocator_ == rhs.baseAllocator_;
}
template<typename U>
bool operator!=(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
{
return !operator==(rhs);
}
//! rapidjson Allocator concept
static const bool kNeedFree = BaseAllocator::kNeedFree;
static const bool kRefCounted = internal::IsRefCounted<BaseAllocator>::Value;
void* Malloc(size_t size)
{
return baseAllocator_.Malloc(size);
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
{
return baseAllocator_.Realloc(originalPtr, originalSize, newSize);
}
static void Free(void *ptr) RAPIDJSON_NOEXCEPT
{
BaseAllocator::Free(ptr);
}
private:
template <typename, typename>
friend class StdAllocator; // access to StdAllocator<!T>.*
BaseAllocator baseAllocator_;
};
#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17
template <typename BaseAllocator>
class StdAllocator<void, BaseAllocator> :
public std::allocator<void>
{
typedef std::allocator<void> allocator_type;
public:
typedef BaseAllocator BaseAllocatorType;
StdAllocator() RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_()
{ }
StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
template<typename U>
StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
/* implicit */
StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_(baseAllocator)
{ }
~StdAllocator() RAPIDJSON_NOEXCEPT
{ }
template<typename U>
struct rebind {
typedef StdAllocator<U, BaseAllocator> other;
};
typedef typename allocator_type::value_type value_type;
private:
template <typename, typename>
friend class StdAllocator; // access to StdAllocator<!T>.*
BaseAllocator baseAllocator_;
};
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ENCODINGS_H_
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_
#define RAPIDJSON_CURSORSTREAMWRAPPER_H_
#include "stream.h"
#if defined(__GNUC__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
#if defined(_MSC_VER) && _MSC_VER <= 1800
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4702) // unreachable code
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Cursor stream wrapper for counting line and column number if error exists.
/*!
\tparam InputStream Any stream that implements Stream Concept
*/
template <typename InputStream, typename Encoding = UTF8<> >
class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {
public:
typedef typename Encoding::Ch Ch;
CursorStreamWrapper(InputStream& is):
GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {}
// counting line and column number
Ch Take() {
Ch ch = this->is_.Take();
if(ch == '\n') {
line_ ++;
col_ = 0;
} else {
col_ ++;
}
return ch;
}
//! Get the error line number, if error exists.
size_t GetLine() const { return line_; }
//! Get the error column number, if error exists.
size_t GetColumn() const { return col_; }
private:
size_t line_; //!< Current Line
size_t col_; //!< Current Column
};
#if defined(_MSC_VER) && _MSC_VER <= 1800
RAPIDJSON_DIAG_POP
#endif
#if defined(__GNUC__)
RAPIDJSON_DIAG_POP
#endif
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_DOCUMENT_H_
#define RAPIDJSON_DOCUMENT_H_
/*! \file document.h */
#include "reader.h"
#include "internal/meta.h"
#include "internal/strfunc.h"
#include "memorystream.h"
#include "encodedstream.h"
#include <new> // placement new
#include <limits>
#ifdef __cpp_lib_three_way_comparison
#include <compare>
#endif
RAPIDJSON_DIAG_PUSH
#ifdef __clang__
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
RAPIDJSON_DIAG_OFF(c++98-compat)
#elif defined(_MSC_VER)
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_OFF(effc++)
#endif // __GNUC__
#ifdef GetObject
// see https://github.com/Tencent/rapidjson/issues/1448
// a former included windows.h might have defined a macro called GetObject, which affects
// GetObject defined here. This ensures the macro does not get applied
#pragma push_macro("GetObject")
#define RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
#undef GetObject
#endif
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
#include <iterator> // std::random_access_iterator_tag
#endif
#if RAPIDJSON_USE_MEMBERSMAP
#include <map> // std::multimap
#endif
RAPIDJSON_NAMESPACE_BEGIN
// Forward declaration.
template <typename Encoding, typename Allocator>
class GenericValue;
template <typename Encoding, typename Allocator, typename StackAllocator>
class GenericDocument;
/*! \def RAPIDJSON_DEFAULT_ALLOCATOR
\ingroup RAPIDJSON_CONFIG
\brief Allows to choose default allocator.
User can define this to use CrtAllocator or MemoryPoolAllocator.
*/
#ifndef RAPIDJSON_DEFAULT_ALLOCATOR
#define RAPIDJSON_DEFAULT_ALLOCATOR MemoryPoolAllocator<CrtAllocator>
#endif
/*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR
\ingroup RAPIDJSON_CONFIG
\brief Allows to choose default stack allocator for Document.
User can define this to use CrtAllocator or MemoryPoolAllocator.
*/
#ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR
#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR CrtAllocator
#endif
/*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY
\ingroup RAPIDJSON_CONFIG
\brief User defined kDefaultObjectCapacity value.
User can define this as any natural number.
*/
#ifndef RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY
// number of objects that rapidjson::Value allocates memory for by default
#define RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY 16
#endif
/*! \def RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY
\ingroup RAPIDJSON_CONFIG
\brief User defined kDefaultArrayCapacity value.
User can define this as any natural number.
*/
#ifndef RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY
// number of array elements that rapidjson::Value allocates memory for by default
#define RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY 16
#endif
//! Name-value pair in a JSON object value.
/*!
This class was internal to GenericValue. It used to be a inner struct.
But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
https://code.google.com/p/rapidjson/issues/detail?id=64
*/
template <typename Encoding, typename Allocator>
class GenericMember {
public:
GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
GenericValue<Encoding, Allocator> value; //!< value of member.
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Move constructor in C++11
GenericMember(GenericMember&& rhs) RAPIDJSON_NOEXCEPT
: name(std::move(rhs.name)),
value(std::move(rhs.value))
{
}
//! Move assignment in C++11
GenericMember& operator=(GenericMember&& rhs) RAPIDJSON_NOEXCEPT {
return *this = static_cast<GenericMember&>(rhs);
}
#endif
//! Assignment with move semantics.
/*! \param rhs Source of the assignment. Its name and value will become a null value after assignment.
*/
GenericMember& operator=(GenericMember& rhs) RAPIDJSON_NOEXCEPT {
if (RAPIDJSON_LIKELY(this != &rhs)) {
name = rhs.name;
value = rhs.value;
}
return *this;
}
// swap() for std::sort() and other potential use in STL.
friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT {
a.name.Swap(b.name);
a.value.Swap(b.value);
}
private:
//! Copy constructor is not permitted.
GenericMember(const GenericMember& rhs);
};
///////////////////////////////////////////////////////////////////////////////
// GenericMemberIterator
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
//! (Constant) member iterator for a JSON object value
/*!
\tparam Const Is this a constant iterator?
\tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
\tparam Allocator Allocator type for allocating memory of object, array and string.
This class implements a Random Access Iterator for GenericMember elements
of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].
\note This iterator implementation is mainly intended to avoid implicit
conversions from iterator values to \c NULL,
e.g. from GenericValue::FindMember.
\note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
pointer-based implementation, if your platform doesn't provide
the C++ <iterator> header.
\see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
*/
template <bool Const, typename Encoding, typename Allocator>
class GenericMemberIterator {
friend class GenericValue<Encoding,Allocator>;
template <bool, typename, typename> friend class GenericMemberIterator;
typedef GenericMember<Encoding,Allocator> PlainType;
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
public:
//! Iterator type itself
typedef GenericMemberIterator Iterator;
//! Constant iterator type
typedef GenericMemberIterator<true,Encoding,Allocator> ConstIterator;
//! Non-constant iterator type
typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;
/** \name std::iterator_traits support */
//@{
typedef ValueType value_type;
typedef ValueType * pointer;
typedef ValueType & reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
//@}
//! Pointer to (const) GenericMember
typedef pointer Pointer;
//! Reference to (const) GenericMember
typedef reference Reference;
//! Signed integer type (e.g. \c ptrdiff_t)
typedef difference_type DifferenceType;
//! Default constructor (singular value)
/*! Creates an iterator pointing to no element.
\note All operations, except for comparisons, are undefined on such values.
*/
GenericMemberIterator() : ptr_() {}
//! Iterator conversions to more const
/*!
\param it (Non-const) iterator to copy from
Allows the creation of an iterator from another GenericMemberIterator
that is "less const". Especially, creating a non-constant iterator
from a constant iterator are disabled:
\li const -> non-const (not ok)
\li const -> const (ok)
\li non-const -> const (ok)
\li non-const -> non-const (ok)
\note If the \c Const template parameter is already \c false, this
constructor effectively defines a regular copy-constructor.
Otherwise, the copy constructor is implicitly defined.
*/
GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; }
//! @name stepping
//@{
Iterator& operator++(){ ++ptr_; return *this; }
Iterator& operator--(){ --ptr_; return *this; }
Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; }
Iterator operator--(int){ Iterator old(*this); --ptr_; return old; }
//@}
//! @name increment/decrement
//@{
Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }
Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }
Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }
Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }
//@}
//! @name relations
//@{
template <bool Const_> bool operator==(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ == that.ptr_; }
template <bool Const_> bool operator!=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ != that.ptr_; }
template <bool Const_> bool operator<=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ <= that.ptr_; }
template <bool Const_> bool operator>=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ >= that.ptr_; }
template <bool Const_> bool operator< (const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ < that.ptr_; }
template <bool Const_> bool operator> (const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ > that.ptr_; }
#ifdef __cpp_lib_three_way_comparison
template <bool Const_> std::strong_ordering operator<=>(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ <=> that.ptr_; }
#endif
//@}
//! @name dereference
//@{
Reference operator*() const { return *ptr_; }
Pointer operator->() const { return ptr_; }
Reference operator[](DifferenceType n) const { return ptr_[n]; }
//@}
//! Distance
DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }
private:
//! Internal constructor from plain pointer
explicit GenericMemberIterator(Pointer p) : ptr_(p) {}
Pointer ptr_; //!< raw pointer
};
#else // RAPIDJSON_NOMEMBERITERATORCLASS
// class-based member iterator implementation disabled, use plain pointers
template <bool Const, typename Encoding, typename Allocator>
class GenericMemberIterator;
//! non-const GenericMemberIterator
template <typename Encoding, typename Allocator>
class GenericMemberIterator<false,Encoding,Allocator> {
public:
//! use plain pointer as iterator type
typedef GenericMember<Encoding,Allocator>* Iterator;
};
//! const GenericMemberIterator
template <typename Encoding, typename Allocator>
class GenericMemberIterator<true,Encoding,Allocator> {
public:
//! use plain const pointer as iterator type
typedef const GenericMember<Encoding,Allocator>* Iterator;
};
#endif // RAPIDJSON_NOMEMBERITERATORCLASS
///////////////////////////////////////////////////////////////////////////////
// GenericStringRef
//! Reference to a constant string (not taking a copy)
/*!
\tparam CharType character type of the string
This helper class is used to automatically infer constant string
references for string literals, especially from \c const \b (!)
character arrays.
The main use is for creating JSON string values without copying the
source string via an \ref Allocator. This requires that the referenced
string pointers have a sufficient lifetime, which exceeds the lifetime
of the associated GenericValue.
\b Example
\code
Value v("foo"); // ok, no need to copy & calculate length
const char foo[] = "foo";
v.SetString(foo); // ok
const char* bar = foo;
// Value x(bar); // not ok, can't rely on bar's lifetime
Value x(StringRef(bar)); // lifetime explicitly guaranteed by user
Value y(StringRef(bar, 3)); // ok, explicitly pass length
\endcode
\see StringRef, GenericValue::SetString
*/
template<typename CharType>
struct GenericStringRef {
typedef CharType Ch; //!< character type of the string
//! Create string reference from \c const character array
#ifndef __clang__ // -Wdocumentation
/*!
This constructor implicitly creates a constant string reference from
a \c const character array. It has better performance than
\ref StringRef(const CharType*) by inferring the string \ref length
from the array length, and also supports strings containing null
characters.
\tparam N length of the string, automatically inferred
\param str Constant character array, lifetime assumed to be longer
than the use of the string in e.g. a GenericValue
\post \ref s == str
\note Constant complexity.
\note There is a hidden, private overload to disallow references to
non-const character arrays to be created via this constructor.
By this, e.g. function-scope arrays used to be filled via
\c snprintf are excluded from consideration.
In such cases, the referenced string should be \b copied to the
GenericValue instead.
*/
#endif
template<SizeType N>
GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
: s(str), length(N-1) {}
//! Explicitly create string reference from \c const character pointer
#ifndef __clang__ // -Wdocumentation
/*!
This constructor can be used to \b explicitly create a reference to
a constant string pointer.
\see StringRef(const CharType*)
\param str Constant character pointer, lifetime assumed to be longer
than the use of the string in e.g. a GenericValue
\post \ref s == str
\note There is a hidden, private overload to disallow references to
non-const character arrays to be created via this constructor.
By this, e.g. function-scope arrays used to be filled via
\c snprintf are excluded from consideration.
In such cases, the referenced string should be \b copied to the
GenericValue instead.
*/
#endif
explicit GenericStringRef(const CharType* str)
: s(str), length(NotNullStrLen(str)) {}
//! Create constant string reference from pointer and length
#ifndef __clang__ // -Wdocumentation
/*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
\param len length of the string, excluding the trailing NULL terminator
\post \ref s == str && \ref length == len
\note Constant complexity.
*/
#endif
GenericStringRef(const CharType* str, SizeType len)
: s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); }
GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
//! implicit conversion to plain CharType pointer
operator const Ch *() const { return s; }
const Ch* const s; //!< plain CharType pointer
const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
private:
SizeType NotNullStrLen(const CharType* str) {
RAPIDJSON_ASSERT(str != 0);
return internal::StrLen(str);
}
/// Empty string - used when passing in a NULL pointer
static const Ch emptyString[];
//! Disallow construction from non-const array
template<SizeType N>
GenericStringRef(CharType (&str)[N]) /* = delete */;
//! Copy assignment operator not permitted - immutable type
GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */;
};
template<typename CharType>
const CharType GenericStringRef<CharType>::emptyString[] = { CharType() };
//! Mark a character pointer as constant string
/*! Mark a plain character pointer as a "string literal". This function
can be used to avoid copying a character string to be referenced as a
value in a JSON GenericValue object, if the string's lifetime is known
to be valid long enough.
\tparam CharType Character type of the string
\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
\return GenericStringRef string reference object
\relatesalso GenericStringRef
\see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember
*/
template<typename CharType>
inline GenericStringRef<CharType> StringRef(const CharType* str) {
return GenericStringRef<CharType>(str);
}
//! Mark a character pointer as constant string
/*! Mark a plain character pointer as a "string literal". This function
can be used to avoid copying a character string to be referenced as a
value in a JSON GenericValue object, if the string's lifetime is known
to be valid long enough.
This version has better performance with supplied length, and also
supports string containing null characters.
\tparam CharType character type of the string
\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
\param length The length of source string.
\return GenericStringRef string reference object
\relatesalso GenericStringRef
*/
template<typename CharType>
inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {
return GenericStringRef<CharType>(str, SizeType(length));
}
#if RAPIDJSON_HAS_STDSTRING
//! Mark a string object as constant string
/*! Mark a string object (e.g. \c std::string) as a "string literal".
This function can be used to avoid copying a string to be referenced as a
value in a JSON GenericValue object, if the string's lifetime is known
to be valid long enough.
\tparam CharType character type of the string
\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
\return GenericStringRef string reference object
\relatesalso GenericStringRef
\note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
*/
template<typename CharType>
inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) {
return GenericStringRef<CharType>(str.data(), SizeType(str.size()));
}
#endif
///////////////////////////////////////////////////////////////////////////////
// GenericValue type traits
namespace internal {
template <typename T, typename Encoding = void, typename Allocator = void>
struct IsGenericValueImpl : FalseType {};
// select candidates according to nested encoding and allocator types
template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>
: IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};
// helper to match arbitrary GenericValue instantiations, including derived classes
template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};
} // namespace internal
///////////////////////////////////////////////////////////////////////////////
// TypeHelper
namespace internal {
template <typename ValueType, typename T>
struct TypeHelper {};
template<typename ValueType>
struct TypeHelper<ValueType, bool> {
static bool Is(const ValueType& v) { return v.IsBool(); }
static bool Get(const ValueType& v) { return v.GetBool(); }
static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); }
static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, int> {
static bool Is(const ValueType& v) { return v.IsInt(); }
static int Get(const ValueType& v) { return v.GetInt(); }
static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); }
static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, unsigned> {
static bool Is(const ValueType& v) { return v.IsUint(); }
static unsigned Get(const ValueType& v) { return v.GetUint(); }
static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); }
static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
};
#ifdef _MSC_VER
RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int));
template<typename ValueType>
struct TypeHelper<ValueType, long> {
static bool Is(const ValueType& v) { return v.IsInt(); }
static long Get(const ValueType& v) { return v.GetInt(); }
static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); }
static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
};
RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned));
template<typename ValueType>
struct TypeHelper<ValueType, unsigned long> {
static bool Is(const ValueType& v) { return v.IsUint(); }
static unsigned long Get(const ValueType& v) { return v.GetUint(); }
static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); }
static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
};
#endif
template<typename ValueType>
struct TypeHelper<ValueType, int64_t> {
static bool Is(const ValueType& v) { return v.IsInt64(); }
static int64_t Get(const ValueType& v) { return v.GetInt64(); }
static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); }
static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, uint64_t> {
static bool Is(const ValueType& v) { return v.IsUint64(); }
static uint64_t Get(const ValueType& v) { return v.GetUint64(); }
static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); }
static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, double> {
static bool Is(const ValueType& v) { return v.IsDouble(); }
static double Get(const ValueType& v) { return v.GetDouble(); }
static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); }
static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, float> {
static bool Is(const ValueType& v) { return v.IsFloat(); }
static float Get(const ValueType& v) { return v.GetFloat(); }
static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); }
static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, const typename ValueType::Ch*> {
typedef const typename ValueType::Ch* StringType;
static bool Is(const ValueType& v) { return v.IsString(); }
static StringType Get(const ValueType& v) { return v.GetString(); }
static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); }
static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
};
#if RAPIDJSON_HAS_STDSTRING
template<typename ValueType>
struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > {
typedef std::basic_string<typename ValueType::Ch> StringType;
static bool Is(const ValueType& v) { return v.IsString(); }
static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); }
static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
};
#endif
template<typename ValueType>
struct TypeHelper<ValueType, typename ValueType::Array> {
typedef typename ValueType::Array ArrayType;
static bool Is(const ValueType& v) { return v.IsArray(); }
static ArrayType Get(ValueType& v) { return v.GetArray(); }
static ValueType& Set(ValueType& v, ArrayType data) { return v = data; }
static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; }
};
template<typename ValueType>
struct TypeHelper<ValueType, typename ValueType::ConstArray> {
typedef typename ValueType::ConstArray ArrayType;
static bool Is(const ValueType& v) { return v.IsArray(); }
static ArrayType Get(const ValueType& v) { return v.GetArray(); }
};
template<typename ValueType>
struct TypeHelper<ValueType, typename ValueType::Object> {
typedef typename ValueType::Object ObjectType;
static bool Is(const ValueType& v) { return v.IsObject(); }
static ObjectType Get(ValueType& v) { return v.GetObject(); }
static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }
static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; }
};
template<typename ValueType>
struct TypeHelper<ValueType, typename ValueType::ConstObject> {
typedef typename ValueType::ConstObject ObjectType;
static bool Is(const ValueType& v) { return v.IsObject(); }
static ObjectType Get(const ValueType& v) { return v.GetObject(); }
};
} // namespace internal
// Forward declarations
template <bool, typename> class GenericArray;
template <bool, typename> class GenericObject;
///////////////////////////////////////////////////////////////////////////////
// GenericValue
//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
/*!
A JSON value can be one of 7 types. This class is a variant type supporting
these types.
Use the Value if UTF8 and default allocator
\tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
\tparam Allocator Allocator type for allocating memory of object, array and string.
*/
template <typename Encoding, typename Allocator = RAPIDJSON_DEFAULT_ALLOCATOR >
class GenericValue {
public:
//! Name-value pair in an object.
typedef GenericMember<Encoding, Allocator> Member;
typedef Encoding EncodingType; //!< Encoding type from template parameter.
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
typedef GenericStringRef<Ch> StringRefType; //!< Reference to a constant string
typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object.
typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object.
typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself.
typedef GenericArray<false, ValueType> Array;
typedef GenericArray<true, ValueType> ConstArray;
typedef GenericObject<false, ValueType> Object;
typedef GenericObject<true, ValueType> ConstObject;
//!@name Constructors and destructor.
//@{
//! Default constructor creates a null value.
GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Move constructor in C++11
GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) {
rhs.data_.f.flags = kNullFlag; // give up contents
}
#endif
private:
//! Copy constructor is not permitted.
GenericValue(const GenericValue& rhs);
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Moving from a GenericDocument is not permitted.
template <typename StackAllocator>
GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
//! Move assignment from a GenericDocument is not permitted.
template <typename StackAllocator>
GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
#endif
public:
//! Constructor with JSON value type.
/*! This creates a Value of specified type with default content.
\param type Type of the value.
\note Default content for number is zero.
*/
explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
static const uint16_t defaultFlags[] = {
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
kNumberAnyFlag
};
RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType);
data_.f.flags = defaultFlags[type];
// Use ShortString to store empty string.
if (type == kStringType)
data_.ss.SetLength(0);
}
//! Explicit copy constructor (with allocator)
/*! Creates a copy of a Value by using the given Allocator
\tparam SourceAllocator allocator of \c rhs
\param rhs Value to copy from (read-only)
\param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
\param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)
\see CopyFrom()
*/
template <typename SourceAllocator>
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
switch (rhs.GetType()) {
case kObjectType:
DoCopyMembers(rhs, allocator, copyConstStrings);
break;
case kArrayType: {
SizeType count = rhs.data_.a.size;
GenericValue* le = reinterpret_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
const GenericValue<Encoding,SourceAllocator>* re = rhs.GetElementsPointer();
for (SizeType i = 0; i < count; i++)
new (&le[i]) GenericValue(re[i], allocator, copyConstStrings);
data_.f.flags = kArrayFlag;
data_.a.size = data_.a.capacity = count;
SetElementsPointer(le);
}
break;
case kStringType:
if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) {
data_.f.flags = rhs.data_.f.flags;
data_ = *reinterpret_cast<const Data*>(&rhs.data_);
}
else
SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
break;
default:
data_.f.flags = rhs.data_.f.flags;
data_ = *reinterpret_cast<const Data*>(&rhs.data_);
break;
}
}
//! Constructor for boolean value.
/*! \param b Boolean value
\note This constructor is limited to \em real boolean values and rejects
implicitly converted types like arbitrary pointers. Use an explicit cast
to \c bool, if you want to construct a boolean JSON value in such cases.
*/
#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
template <typename T>
explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<bool, T>))) RAPIDJSON_NOEXCEPT // See #472
#else
explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
#endif
: data_() {
// safe-guard against failing SFINAE
RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
data_.f.flags = b ? kTrueFlag : kFalseFlag;
}
//! Constructor for int value.
explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() {
data_.n.i64 = i;
data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag;
}
//! Constructor for unsigned value.
explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() {
data_.n.u64 = u;
data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag);
}
//! Constructor for int64_t value.
explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() {
data_.n.i64 = i64;
data_.f.flags = kNumberInt64Flag;
if (i64 >= 0) {
data_.f.flags |= kNumberUint64Flag;
if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
data_.f.flags |= kUintFlag;
if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
data_.f.flags |= kIntFlag;
}
else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
data_.f.flags |= kIntFlag;
}
//! Constructor for uint64_t value.
explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() {
data_.n.u64 = u64;
data_.f.flags = kNumberUint64Flag;
if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
data_.f.flags |= kInt64Flag;
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
data_.f.flags |= kUintFlag;
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
data_.f.flags |= kIntFlag;
}
//! Constructor for double value.
explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }
//! Constructor for float value.
explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast<double>(f); data_.f.flags = kNumberDoubleFlag; }
//! Constructor for constant string (i.e. do not make a copy of string)
GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
//! Constructor for constant string (i.e. do not make a copy of string)
explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }
//! Constructor for copy-string (i.e. do make a copy of string)
GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); }
//! Constructor for copy-string (i.e. do make a copy of string)
GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
#if RAPIDJSON_HAS_STDSTRING
//! Constructor for copy-string from a string object (i.e. do make a copy of string)
/*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
*/
GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
#endif
//! Constructor for Array.
/*!
\param a An array obtained by \c GetArray().
\note \c Array is always pass-by-value.
\note the source array is moved into this value and the sourec array becomes empty.
*/
GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) {
a.value_.data_ = Data();
a.value_.data_.f.flags = kArrayFlag;
}
//! Constructor for Object.
/*!
\param o An object obtained by \c GetObject().
\note \c Object is always pass-by-value.
\note the source object is moved into this value and the sourec object becomes empty.
*/
GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) {
o.value_.data_ = Data();
o.value_.data_.f.flags = kObjectFlag;
}
//! Destructor.
/*! Need to destruct elements of array, members of object, or copy-string.
*/
~GenericValue() {
// With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release
// their Allocator if it's refcounted (e.g. MemoryPoolAllocator).
if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 &&
internal::IsRefCounted<Allocator>::Value)) {
switch(data_.f.flags) {
case kArrayFlag:
{
GenericValue* e = GetElementsPointer();
for (GenericValue* v = e; v != e + data_.a.size; ++v)
v->~GenericValue();
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
Allocator::Free(e);
}
}
break;
case kObjectFlag:
DoFreeMembers();
break;
case kCopyStringFlag:
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
Allocator::Free(const_cast<Ch*>(GetStringPointer()));
}
break;
default:
break; // Do nothing for other types.
}
}
}
//@}
//!@name Assignment operators
//@{
//! Assignment with move semantics.
/*! \param rhs Source of the assignment. It will become a null value after assignment.
*/
GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
if (RAPIDJSON_LIKELY(this != &rhs)) {
// Can't destroy "this" before assigning "rhs", otherwise "rhs"
// could be used after free if it's an sub-Value of "this",
// hence the temporary danse.
GenericValue temp;
temp.RawAssign(rhs);
this->~GenericValue();
RawAssign(temp);
}
return *this;
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Move assignment in C++11
GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {
return *this = rhs.Move();
}
#endif
//! Assignment of constant string reference (no copy)
/*! \param str Constant string reference to be assigned
\note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
\see GenericStringRef, operator=(T)
*/
GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {
GenericValue s(str);
return *this = s;
}
//! Assignment with primitive types.
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
\param value The value to be assigned.
\note The source type \c T explicitly disallows all pointer types,
especially (\c const) \ref Ch*. This helps avoiding implicitly
referencing character strings with insufficient lifetime, use
\ref SetString(const Ch*, Allocator&) (for copying) or
\ref StringRef() (to explicitly mark the pointer as constant) instead.
All other pointer types would implicitly convert to \c bool,
use \ref SetBool() instead.
*/
template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
operator=(T value) {
GenericValue v(value);
return *this = v;
}
//! Deep-copy assignment from Value
/*! Assigns a \b copy of the Value to the current Value object
\tparam SourceAllocator Allocator type of \c rhs
\param rhs Value to copy from (read-only)
\param allocator Allocator to use for copying
\param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)
*/
template <typename SourceAllocator>
GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));
this->~GenericValue();
new (this) GenericValue(rhs, allocator, copyConstStrings);
return *this;
}
//! Exchange the contents of this value with those of other.
/*!
\param other Another value.
\note Constant complexity.
*/
GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
GenericValue temp;
temp.RawAssign(*this);
RawAssign(other);
other.RawAssign(temp);
return *this;
}
//! free-standing swap function helper
/*!
Helper function to enable support for common swap implementation pattern based on \c std::swap:
\code
void swap(MyClass& a, MyClass& b) {
using std::swap;
swap(a.value, b.value);
// ...
}
\endcode
\see Swap()
*/
friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
//! Prepare Value for move semantics
/*! \return *this */
GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
//@}
//!@name Equal-to and not-equal-to operators
//@{
//! Equal-to operator
/*!
\note If an object contains duplicated named member, comparing equality with any object is always \c false.
\note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings).
*/
template <typename SourceAllocator>
bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
typedef GenericValue<Encoding, SourceAllocator> RhsType;
if (GetType() != rhs.GetType())
return false;
switch (GetType()) {
case kObjectType: // Warning: O(n^2) inner-loop
if (data_.o.size != rhs.data_.o.size)
return false;
for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
return false;
}
return true;
case kArrayType:
if (data_.a.size != rhs.data_.a.size)
return false;
for (SizeType i = 0; i < data_.a.size; i++)
if ((*this)[i] != rhs[i])
return false;
return true;
case kStringType:
return StringEqual(rhs);
case kNumberType:
if (IsDouble() || rhs.IsDouble()) {
double a = GetDouble(); // May convert from integer to double.
double b = rhs.GetDouble(); // Ditto
return a >= b && a <= b; // Prevent -Wfloat-equal
}
else
return data_.n.u64 == rhs.data_.n.u64;
default:
return true;
}
}
//! Equal-to operator with const C-string pointer
bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }
#if RAPIDJSON_HAS_STDSTRING
//! Equal-to operator with string object
/*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
*/
bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); }
#endif
//! Equal-to operator with primitive types
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
*/
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
//! Not-equal-to operator
/*! \return !(*this == rhs)
*/
template <typename SourceAllocator>
bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }
//! Not-equal-to operator with const C-string pointer
bool operator!=(const Ch* rhs) const { return !(*this == rhs); }
//! Not-equal-to operator with arbitrary types
/*! \return !(*this == rhs)
*/
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
#ifndef __cpp_lib_three_way_comparison
//! Equal-to operator with arbitrary types (symmetric version)
/*! \return (rhs == lhs)
*/
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
//! Not-Equal-to operator with arbitrary types (symmetric version)
/*! \return !(rhs == lhs)
*/
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
//@}
#endif
//!@name Type
//@{
Type GetType() const { return static_cast<Type>(data_.f.flags & kTypeMask); }
bool IsNull() const { return data_.f.flags == kNullFlag; }
bool IsFalse() const { return data_.f.flags == kFalseFlag; }
bool IsTrue() const { return data_.f.flags == kTrueFlag; }
bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; }
bool IsObject() const { return data_.f.flags == kObjectFlag; }
bool IsArray() const { return data_.f.flags == kArrayFlag; }
bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }
bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; }
bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; }
bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; }
bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }
bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; }
bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }
// Checks whether a number can be losslessly converted to a double.
bool IsLosslessDouble() const {
if (!IsNumber()) return false;
if (IsUint64()) {
uint64_t u = GetUint64();
volatile double d = static_cast<double>(u);
return (d >= 0.0)
&& (d < static_cast<double>((std::numeric_limits<uint64_t>::max)()))
&& (u == static_cast<uint64_t>(d));
}
if (IsInt64()) {
int64_t i = GetInt64();
volatile double d = static_cast<double>(i);
return (d >= static_cast<double>((std::numeric_limits<int64_t>::min)()))
&& (d < static_cast<double>((std::numeric_limits<int64_t>::max)()))
&& (i == static_cast<int64_t>(d));
}
return true; // double, int, uint are always lossless
}
// Checks whether a number is a float (possible lossy).
bool IsFloat() const {
if ((data_.f.flags & kDoubleFlag) == 0)
return false;
double d = GetDouble();
return d >= -3.4028234e38 && d <= 3.4028234e38;
}
// Checks whether a number can be losslessly converted to a float.
bool IsLosslessFloat() const {
if (!IsNumber()) return false;
double a = GetDouble();
if (a < static_cast<double>(-(std::numeric_limits<float>::max)())
|| a > static_cast<double>((std::numeric_limits<float>::max)()))
return false;
double b = static_cast<double>(static_cast<float>(a));
return a >= b && a <= b; // Prevent -Wfloat-equal
}
//@}
//!@name Null
//@{
GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
//@}
//!@name Bool
//@{
bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; }
//!< Set boolean value
/*! \post IsBool() == true */
GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
//@}
//!@name Object
//@{
//! Set this value as an empty object.
/*! \post IsObject() == true */
GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
//! Get the number of members in the object.
SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
//! Get the capacity of object.
SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; }
//! Check whether the object is empty.
bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
//! Get a value from an object associated with the name.
/*! \pre IsObject() == true
\tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType))
\note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.
Since 0.2, if the name is not correct, it will assert.
If user is unsure whether a member exists, user should use HasMember() first.
A better approach is to use FindMember().
\note Linear time complexity.
*/
template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {
GenericValue n(StringRef(name));
return (*this)[n];
}
template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }
//! Get a value from an object associated with the name.
/*! \pre IsObject() == true
\tparam SourceAllocator Allocator of the \c name value
\note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen().
And it can also handle strings with embedded null characters.
\note Linear time complexity.
*/
template <typename SourceAllocator>
GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator member = FindMember(name);
if (member != MemberEnd())
return member->value;
else {
RAPIDJSON_ASSERT(false); // see above note
// This will generate -Wexit-time-destructors in clang
// static GenericValue NullValue;
// return NullValue;
// Use static buffer and placement-new to prevent destruction
static char buffer[sizeof(GenericValue)];
return *new (buffer) GenericValue();
}
}
template <typename SourceAllocator>
const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
#if RAPIDJSON_HAS_STDSTRING
//! Get a value from an object associated with name (string object).
GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }
const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }
#endif
//! Const member iterator
/*! \pre IsObject() == true */
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); }
//! Const \em past-the-end member iterator
/*! \pre IsObject() == true */
ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); }
//! Member iterator
/*! \pre IsObject() == true */
MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); }
//! \em Past-the-end member iterator
/*! \pre IsObject() == true */
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
//! Request the object to have enough capacity to store members.
/*! \param newCapacity The capacity that the object at least need to have.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\note Linear time complexity.
*/
GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) {
RAPIDJSON_ASSERT(IsObject());
DoReserveMembers(newCapacity, allocator);
return *this;
}
//! Check whether a member exists in the object.
/*!
\param name Member name to be searched.
\pre IsObject() == true
\return Whether a member with that name exists.
\note It is better to use FindMember() directly if you need the obtain the value as well.
\note Linear time complexity.
*/
bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
#if RAPIDJSON_HAS_STDSTRING
//! Check whether a member exists in the object with string object.
/*!
\param name Member name to be searched.
\pre IsObject() == true
\return Whether a member with that name exists.
\note It is better to use FindMember() directly if you need the obtain the value as well.
\note Linear time complexity.
*/
bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }
#endif
//! Check whether a member exists in the object with GenericValue name.
/*!
This version is faster because it does not need a StrLen(). It can also handle string with null character.
\param name Member name to be searched.
\pre IsObject() == true
\return Whether a member with that name exists.
\note It is better to use FindMember() directly if you need the obtain the value as well.
\note Linear time complexity.
*/
template <typename SourceAllocator>
bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }
//! Find member by name.
/*!
\param name Member name to be searched.
\pre IsObject() == true
\return Iterator to member, if it exists.
Otherwise returns \ref MemberEnd().
\note Earlier versions of Rapidjson returned a \c NULL pointer, in case
the requested member doesn't exist. For consistency with e.g.
\c std::map, this has been changed to MemberEnd() now.
\note Linear time complexity.
*/
MemberIterator FindMember(const Ch* name) {
GenericValue n(StringRef(name));
return FindMember(n);
}
ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
//! Find member by name.
/*!
This version is faster because it does not need a StrLen(). It can also handle string with null character.
\param name Member name to be searched.
\pre IsObject() == true
\return Iterator to member, if it exists.
Otherwise returns \ref MemberEnd().
\note Earlier versions of Rapidjson returned a \c NULL pointer, in case
the requested member doesn't exist. For consistency with e.g.
\c std::map, this has been changed to MemberEnd() now.
\note Linear time complexity.
*/
template <typename SourceAllocator>
MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString());
return DoFindMember(name);
}
template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
#if RAPIDJSON_HAS_STDSTRING
//! Find member by string object name.
/*!
\param name Member name to be searched.
\pre IsObject() == true
\return Iterator to member, if it exists.
Otherwise returns \ref MemberEnd().
*/
MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(GenericValue(StringRef(name))); }
ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(GenericValue(StringRef(name))); }
#endif
//! Add a member (name-value pair) to the object.
/*! \param name A string value as name of member.
\param value Value of any type.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\note The ownership of \c name and \c value will be transferred to this object on success.
\pre IsObject() && name.IsString()
\post name.IsNull() && value.IsNull()
\note Amortized Constant time complexity.
*/
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString());
DoAddMember(name, value, allocator);
return *this;
}
//! Add a constant string value as member (name-value pair) to the object.
/*! \param name A string value as name of member.
\param value constant string reference as value of member.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\pre IsObject()
\note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
\note Amortized Constant time complexity.
*/
GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {
GenericValue v(value);
return AddMember(name, v, allocator);
}
#if RAPIDJSON_HAS_STDSTRING
//! Add a string object as member (name-value pair) to the object.
/*! \param name A string value as name of member.
\param value constant string reference as value of member.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\pre IsObject()
\note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
\note Amortized Constant time complexity.
*/
GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {
GenericValue v(value, allocator);
return AddMember(name, v, allocator);
}
#endif
//! Add any primitive value as member (name-value pair) to the object.
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
\param name A string value as name of member.
\param value Value of primitive type \c T as value of member
\param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\pre IsObject()
\note The source type \c T explicitly disallows all pointer types,
especially (\c const) \ref Ch*. This helps avoiding implicitly
referencing character strings with insufficient lifetime, use
\ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
AddMember(StringRefType, StringRefType, Allocator&).
All other pointer types would implicitly convert to \c bool,
use an explicit cast instead, if needed.
\note Amortized Constant time complexity.
*/
template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
AddMember(GenericValue& name, T value, Allocator& allocator) {
GenericValue v(value);
return AddMember(name, v, allocator);
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {
return AddMember(name, value, allocator);
}
GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {
return AddMember(name, value, allocator);
}
GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {
return AddMember(name, value, allocator);
}
GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {
GenericValue n(name);
return AddMember(n, value, allocator);
}
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Add a member (name-value pair) to the object.
/*! \param name A constant string reference as name of member.
\param value Value of any type.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\note The ownership of \c value will be transferred to this object on success.
\pre IsObject()
\post value.IsNull()
\note Amortized Constant time complexity.
*/
GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {
GenericValue n(name);
return AddMember(n, value, allocator);
}
//! Add a constant string value as member (name-value pair) to the object.
/*! \param name A constant string reference as name of member.
\param value constant string reference as value of member.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\pre IsObject()
\note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.
\note Amortized Constant time complexity.
*/
GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
GenericValue v(value);
return AddMember(name, v, allocator);
}
//! Add any primitive value as member (name-value pair) to the object.
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
\param name A constant string reference as name of member.
\param value Value of primitive type \c T as value of member
\param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\pre IsObject()
\note The source type \c T explicitly disallows all pointer types,
especially (\c const) \ref Ch*. This helps avoiding implicitly
referencing character strings with insufficient lifetime, use
\ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
AddMember(StringRefType, StringRefType, Allocator&).
All other pointer types would implicitly convert to \c bool,
use an explicit cast instead, if needed.
\note Amortized Constant time complexity.
*/
template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
AddMember(StringRefType name, T value, Allocator& allocator) {
GenericValue n(name);
return AddMember(n, value, allocator);
}
//! Remove all members in the object.
/*! This function do not deallocate memory in the object, i.e. the capacity is unchanged.
\note Linear time complexity.
*/
void RemoveAllMembers() {
RAPIDJSON_ASSERT(IsObject());
DoClearMembers();
}
//! Remove a member in object by its name.
/*! \param name Name of member to be removed.
\return Whether the member existed.
\note This function may reorder the object members. Use \ref
EraseMember(ConstMemberIterator) if you need to preserve the
relative order of the remaining members.
\note Linear time complexity.
*/
bool RemoveMember(const Ch* name) {
GenericValue n(StringRef(name));
return RemoveMember(n);
}
#if RAPIDJSON_HAS_STDSTRING
bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }
#endif
template <typename SourceAllocator>
bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator m = FindMember(name);
if (m != MemberEnd()) {
RemoveMember(m);
return true;
}
else
return false;
}
//! Remove a member in object by iterator.
/*! \param m member iterator (obtained by FindMember() or MemberBegin()).
\return the new iterator after removal.
\note This function may reorder the object members. Use \ref
EraseMember(ConstMemberIterator) if you need to preserve the
relative order of the remaining members.
\note Constant time complexity.
*/
MemberIterator RemoveMember(MemberIterator m) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(data_.o.size > 0);
RAPIDJSON_ASSERT(GetMembersPointer() != 0);
RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
return DoRemoveMember(m);
}
//! Remove a member from an object by iterator.
/*! \param pos iterator to the member to remove
\pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd()
\return Iterator following the removed element.
If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned.
\note This function preserves the relative order of the remaining object
members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator).
\note Linear time complexity.
*/
MemberIterator EraseMember(ConstMemberIterator pos) {
return EraseMember(pos, pos +1);
}
//! Remove members in the range [first, last) from an object.
/*! \param first iterator to the first member to remove
\param last iterator following the last member to remove
\pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd()
\return Iterator following the last removed element.
\note This function preserves the relative order of the remaining object
members.
\note Linear time complexity.
*/
MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(data_.o.size > 0);
RAPIDJSON_ASSERT(GetMembersPointer() != 0);
RAPIDJSON_ASSERT(first >= MemberBegin());
RAPIDJSON_ASSERT(first <= last);
RAPIDJSON_ASSERT(last <= MemberEnd());
return DoEraseMembers(first, last);
}
//! Erase a member in object by its name.
/*! \param name Name of member to be removed.
\return Whether the member existed.
\note Linear time complexity.
*/
bool EraseMember(const Ch* name) {
GenericValue n(StringRef(name));
return EraseMember(n);
}
#if RAPIDJSON_HAS_STDSTRING
bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }
#endif
template <typename SourceAllocator>
bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator m = FindMember(name);
if (m != MemberEnd()) {
EraseMember(m);
return true;
}
else
return false;
}
Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
Object GetObj() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
ConstObject GetObj() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
//@}
//!@name Array
//@{
//! Set this value as an empty array.
/*! \post IsArray == true */
GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
//! Get the number of elements in array.
SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
//! Get the capacity of array.
SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
//! Check whether the array is empty.
bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
//! Remove all elements in the array.
/*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
\note Linear time complexity.
*/
void Clear() {
RAPIDJSON_ASSERT(IsArray());
GenericValue* e = GetElementsPointer();
for (GenericValue* v = e; v != e + data_.a.size; ++v)
v->~GenericValue();
data_.a.size = 0;
}
//! Get an element from array by index.
/*! \pre IsArray() == true
\param index Zero-based index of element.
\see operator[](T*)
*/
GenericValue& operator[](SizeType index) {
RAPIDJSON_ASSERT(IsArray());
RAPIDJSON_ASSERT(index < data_.a.size);
return GetElementsPointer()[index];
}
const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
//! Element iterator
/*! \pre IsArray() == true */
ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); }
//! \em Past-the-end element iterator
/*! \pre IsArray() == true */
ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; }
//! Constant element iterator
/*! \pre IsArray() == true */
ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
//! Constant \em past-the-end element iterator
/*! \pre IsArray() == true */
ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
//! Request the array to have enough capacity to store elements.
/*! \param newCapacity The capacity that the array at least need to have.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\note Linear time complexity.
*/
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
RAPIDJSON_ASSERT(IsArray());
if (newCapacity > data_.a.capacity) {
SetElementsPointer(reinterpret_cast<GenericValue*>(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue))));
data_.a.capacity = newCapacity;
}
return *this;
}
//! Append a GenericValue at the end of the array.
/*! \param value Value to be appended.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\pre IsArray() == true
\post value.IsNull() == true
\return The value itself for fluent API.
\note The ownership of \c value will be transferred to this array on success.
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
\note Amortized constant time complexity.
*/
GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
RAPIDJSON_ASSERT(IsArray());
if (data_.a.size >= data_.a.capacity)
Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
GetElementsPointer()[data_.a.size++].RawAssign(value);
return *this;
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {
return PushBack(value, allocator);
}
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Append a constant string reference at the end of the array.
/*! \param value Constant string reference to be appended.
\param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().
\pre IsArray() == true
\return The value itself for fluent API.
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
\note Amortized constant time complexity.
\see GenericStringRef
*/
GenericValue& PushBack(StringRefType value, Allocator& allocator) {
return (*this).template PushBack<StringRefType>(value, allocator);
}
//! Append a primitive value at the end of the array.
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
\param value Value of primitive type T to be appended.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\pre IsArray() == true
\return The value itself for fluent API.
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
\note The source type \c T explicitly disallows all pointer types,
especially (\c const) \ref Ch*. This helps avoiding implicitly
referencing character strings with insufficient lifetime, use
\ref PushBack(GenericValue&, Allocator&) or \ref
PushBack(StringRefType, Allocator&).
All other pointer types would implicitly convert to \c bool,
use an explicit cast instead, if needed.
\note Amortized constant time complexity.
*/
template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
PushBack(T value, Allocator& allocator) {
GenericValue v(value);
return PushBack(v, allocator);
}
//! Remove the last element in the array.
/*!
\note Constant time complexity.
*/
GenericValue& PopBack() {
RAPIDJSON_ASSERT(IsArray());
RAPIDJSON_ASSERT(!Empty());
GetElementsPointer()[--data_.a.size].~GenericValue();
return *this;
}
//! Remove an element of array by iterator.
/*!
\param pos iterator to the element to remove
\pre IsArray() == true && \ref Begin() <= \c pos < \ref End()
\return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.
\note Linear time complexity.
*/
ValueIterator Erase(ConstValueIterator pos) {
return Erase(pos, pos + 1);
}
//! Remove elements in the range [first, last) of the array.
/*!
\param first iterator to the first element to remove
\param last iterator following the last element to remove
\pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End()
\return Iterator following the last removed element.
\note Linear time complexity.
*/
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
RAPIDJSON_ASSERT(IsArray());
RAPIDJSON_ASSERT(data_.a.size > 0);
RAPIDJSON_ASSERT(GetElementsPointer() != 0);
RAPIDJSON_ASSERT(first >= Begin());
RAPIDJSON_ASSERT(first <= last);
RAPIDJSON_ASSERT(last <= End());
ValueIterator pos = Begin() + (first - Begin());
for (ValueIterator itr = pos; itr != last; ++itr)
itr->~GenericValue();
std::memmove(static_cast<void*>(pos), last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
data_.a.size -= static_cast<SizeType>(last - first);
return pos;
}
Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); }
ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); }
//@}
//!@name Number
//@{
int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; }
unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; }
int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; }
uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; }
//! Get the value as double type.
/*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless.
*/
double GetDouble() const {
RAPIDJSON_ASSERT(IsNumber());
if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double
if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
if ((data_.f.flags & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
}
//! Get the value as float type.
/*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless.
*/
float GetFloat() const {
return static_cast<float>(GetDouble());
}
GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; }
GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast<double>(f)); return *this; }
//@}
//!@name String
//@{
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); }
//! Get the length of string.
/*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
*/
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); }
//! Set this value as a string without copying source string.
/*! This version has better performance with supplied length, and also support string containing null character.
\param s source string pointer.
\param length The length of source string, excluding the trailing null terminator.
\return The value itself for fluent API.
\post IsString() == true && GetString() == s && GetStringLength() == length
\see SetString(StringRefType)
*/
GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }
//! Set this value as a string without copying source string.
/*! \param s source string reference
\return The value itself for fluent API.
\post IsString() == true && GetString() == s && GetStringLength() == s.length
*/
GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }
//! Set this value as a string by copying from source string.
/*! This version has better performance with supplied length, and also support string containing null character.
\param s source string.
\param length The length of source string, excluding the trailing null terminator.
\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
*/
GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); }
//! Set this value as a string by copying from source string.
/*! \param s source string.
\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
*/
GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
//! Set this value as a string by copying from source string.
/*! \param s source string reference
\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length
*/
GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; }
#if RAPIDJSON_HAS_STDSTRING
//! Set this value as a string by copying from source string.
/*! \param s source string.
\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
\note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
*/
GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
#endif
//@}
//!@name Array
//@{
//! Templated version for checking whether this value is type T.
/*!
\tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string<Ch>
*/
template <typename T>
bool Is() const { return internal::TypeHelper<ValueType, T>::Is(*this); }
template <typename T>
T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); }
template <typename T>
T Get() { return internal::TypeHelper<ValueType, T>::Get(*this); }
template<typename T>
ValueType& Set(const T& data) { return internal::TypeHelper<ValueType, T>::Set(*this, data); }
template<typename T>
ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper<ValueType, T>::Set(*this, data, allocator); }
//@}
//! Generate events of this value to a Handler.
/*! This function adopts the GoF visitor pattern.
Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
It can also be used to deep clone this value via GenericDocument, which is also a Handler.
\tparam Handler type of handler.
\param handler An object implementing concept Handler.
*/
template <typename Handler>
bool Accept(Handler& handler) const {
switch(GetType()) {
case kNullType: return handler.Null();
case kFalseType: return handler.Bool(false);
case kTrueType: return handler.Bool(true);
case kObjectType:
if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
return false;
for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0)))
return false;
if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))
return false;
}
return handler.EndObject(data_.o.size);
case kArrayType:
if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
return false;
for (ConstValueIterator v = Begin(); v != End(); ++v)
if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
return false;
return handler.EndArray(data_.a.size);
case kStringType:
return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0);
default:
RAPIDJSON_ASSERT(GetType() == kNumberType);
if (IsDouble()) return handler.Double(data_.n.d);
else if (IsInt()) return handler.Int(data_.n.i.i);
else if (IsUint()) return handler.Uint(data_.n.u.u);
else if (IsInt64()) return handler.Int64(data_.n.i64);
else return handler.Uint64(data_.n.u64);
}
}
private:
template <typename, typename> friend class GenericValue;
template <typename, typename, typename> friend class GenericDocument;
enum {
kBoolFlag = 0x0008,
kNumberFlag = 0x0010,
kIntFlag = 0x0020,
kUintFlag = 0x0040,
kInt64Flag = 0x0080,
kUint64Flag = 0x0100,
kDoubleFlag = 0x0200,
kStringFlag = 0x0400,
kCopyFlag = 0x0800,
kInlineStrFlag = 0x1000,
// Initial flags of different types.
kNullFlag = kNullType,
// These casts are added to suppress the warning on MSVC about bitwise operations between enums of different types.
kTrueFlag = static_cast<int>(kTrueType) | static_cast<int>(kBoolFlag),
kFalseFlag = static_cast<int>(kFalseType) | static_cast<int>(kBoolFlag),
kNumberIntFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag),
kNumberUintFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag),
kNumberInt64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kInt64Flag),
kNumberUint64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUint64Flag),
kNumberDoubleFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kDoubleFlag),
kNumberAnyFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag),
kConstStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag),
kCopyStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag),
kShortStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag | kInlineStrFlag),
kObjectFlag = kObjectType,
kArrayFlag = kArrayType,
kTypeMask = 0x07
};
static const SizeType kDefaultArrayCapacity = RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY;
static const SizeType kDefaultObjectCapacity = RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY;
struct Flag {
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer
#elif RAPIDJSON_64BIT
char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes
#else
char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes
#endif
uint16_t flags;
};
struct String {
SizeType length;
SizeType hashcode; //!< reserved
const Ch* str;
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
// implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
// (excluding the terminating zero) and store a value to determine the length of the contained
// string in the last character str[LenPos] by storing "MaxSize - length" there. If the string
// to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
// the string terminator as well. For getting the string length back from that value just use
// "MaxSize - str[LenPos]".
// This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode,
// 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings).
struct ShortString {
enum { MaxChars = sizeof(static_cast<Flag*>(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
Ch str[MaxChars];
inline static bool Usable(SizeType len) { return (MaxSize >= len); }
inline void SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize - len); }
inline SizeType GetLength() const { return static_cast<SizeType>(MaxSize - str[LenPos]); }
}; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
// By using proper binary layout, retrieval of different integer types do not need conversions.
union Number {
#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
struct I {
int i;
char padding[4];
}i;
struct U {
unsigned u;
char padding2[4];
}u;
#else
struct I {
char padding[4];
int i;
}i;
struct U {
char padding2[4];
unsigned u;
}u;
#endif
int64_t i64;
uint64_t u64;
double d;
}; // 8 bytes
struct ObjectData {
SizeType size;
SizeType capacity;
Member* members;
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
struct ArrayData {
SizeType size;
SizeType capacity;
GenericValue* elements;
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
union Data {
String s;
ShortString ss;
Number n;
ObjectData o;
ArrayData a;
Flag f;
}; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) {
return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str);
}
static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) {
return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length;
}
RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); }
RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
#if RAPIDJSON_USE_MEMBERSMAP
struct MapTraits {
struct Less {
bool operator()(const Data& s1, const Data& s2) const {
SizeType n1 = DataStringLength(s1), n2 = DataStringLength(s2);
int cmp = std::memcmp(DataString(s1), DataString(s2), sizeof(Ch) * (n1 < n2 ? n1 : n2));
return cmp < 0 || (cmp == 0 && n1 < n2);
}
};
typedef std::pair<const Data, SizeType> Pair;
typedef std::multimap<Data, SizeType, Less, StdAllocator<Pair, Allocator> > Map;
typedef typename Map::iterator Iterator;
};
typedef typename MapTraits::Map Map;
typedef typename MapTraits::Less MapLess;
typedef typename MapTraits::Pair MapPair;
typedef typename MapTraits::Iterator MapIterator;
//
// Layout of the members' map/array, re(al)located according to the needed capacity:
//
// {Map*}<>{capacity}<>{Member[capacity]}<>{MapIterator[capacity]}
//
// (where <> stands for the RAPIDJSON_ALIGN-ment, if needed)
//
static RAPIDJSON_FORCEINLINE size_t GetMapLayoutSize(SizeType capacity) {
return RAPIDJSON_ALIGN(sizeof(Map*)) +
RAPIDJSON_ALIGN(sizeof(SizeType)) +
RAPIDJSON_ALIGN(capacity * sizeof(Member)) +
capacity * sizeof(MapIterator);
}
static RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(Map* &map) {
return *reinterpret_cast<SizeType*>(reinterpret_cast<uintptr_t>(&map) +
RAPIDJSON_ALIGN(sizeof(Map*)));
}
static RAPIDJSON_FORCEINLINE Member* GetMapMembers(Map* &map) {
return reinterpret_cast<Member*>(reinterpret_cast<uintptr_t>(&map) +
RAPIDJSON_ALIGN(sizeof(Map*)) +
RAPIDJSON_ALIGN(sizeof(SizeType)));
}
static RAPIDJSON_FORCEINLINE MapIterator* GetMapIterators(Map* &map) {
return reinterpret_cast<MapIterator*>(reinterpret_cast<uintptr_t>(&map) +
RAPIDJSON_ALIGN(sizeof(Map*)) +
RAPIDJSON_ALIGN(sizeof(SizeType)) +
RAPIDJSON_ALIGN(GetMapCapacity(map) * sizeof(Member)));
}
static RAPIDJSON_FORCEINLINE Map* &GetMap(Member* members) {
RAPIDJSON_ASSERT(members != 0);
return *reinterpret_cast<Map**>(reinterpret_cast<uintptr_t>(members) -
RAPIDJSON_ALIGN(sizeof(SizeType)) -
RAPIDJSON_ALIGN(sizeof(Map*)));
}
// Some compilers' debug mechanisms want all iterators to be destroyed, for their accounting..
RAPIDJSON_FORCEINLINE MapIterator DropMapIterator(MapIterator& rhs) {
#if RAPIDJSON_HAS_CXX11
MapIterator ret = std::move(rhs);
#else
MapIterator ret = rhs;
#endif
rhs.~MapIterator();
return ret;
}
Map* &DoReallocMap(Map** oldMap, SizeType newCapacity, Allocator& allocator) {
Map **newMap = static_cast<Map**>(allocator.Malloc(GetMapLayoutSize(newCapacity)));
GetMapCapacity(*newMap) = newCapacity;
if (!oldMap) {
*newMap = new (allocator.Malloc(sizeof(Map))) Map(MapLess(), allocator);
}
else {
*newMap = *oldMap;
size_t count = (*oldMap)->size();
std::memcpy(static_cast<void*>(GetMapMembers(*newMap)),
static_cast<void*>(GetMapMembers(*oldMap)),
count * sizeof(Member));
MapIterator *oldIt = GetMapIterators(*oldMap),
*newIt = GetMapIterators(*newMap);
while (count--) {
new (&newIt[count]) MapIterator(DropMapIterator(oldIt[count]));
}
Allocator::Free(oldMap);
}
return *newMap;
}
RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
return GetMapMembers(DoReallocMap(0, capacity, allocator));
}
void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
ObjectData& o = data_.o;
if (newCapacity > o.capacity) {
Member* oldMembers = GetMembersPointer();
Map **oldMap = oldMembers ? &GetMap(oldMembers) : 0,
*&newMap = DoReallocMap(oldMap, newCapacity, allocator);
RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap));
o.capacity = newCapacity;
}
}
template <typename SourceAllocator>
MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
if (Member* members = GetMembersPointer()) {
Map* &map = GetMap(members);
MapIterator mit = map->find(reinterpret_cast<const Data&>(name.data_));
if (mit != map->end()) {
return MemberIterator(&members[mit->second]);
}
}
return MemberEnd();
}
void DoClearMembers() {
if (Member* members = GetMembersPointer()) {
Map* &map = GetMap(members);
MapIterator* mit = GetMapIterators(map);
for (SizeType i = 0; i < data_.o.size; i++) {
map->erase(DropMapIterator(mit[i]));
members[i].~Member();
}
data_.o.size = 0;
}
}
void DoFreeMembers() {
if (Member* members = GetMembersPointer()) {
GetMap(members)->~Map();
for (SizeType i = 0; i < data_.o.size; i++) {
members[i].~Member();
}
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
Map** map = &GetMap(members);
Allocator::Free(*map);
Allocator::Free(map);
}
}
}
#else // !RAPIDJSON_USE_MEMBERSMAP
RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
return Malloc<Member>(allocator, capacity);
}
void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
ObjectData& o = data_.o;
if (newCapacity > o.capacity) {
Member* newMembers = Realloc<Member>(allocator, GetMembersPointer(), o.capacity, newCapacity);
RAPIDJSON_SETPOINTER(Member, o.members, newMembers);
o.capacity = newCapacity;
}
}
template <typename SourceAllocator>
MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator member = MemberBegin();
for ( ; member != MemberEnd(); ++member)
if (name.StringEqual(member->name))
break;
return member;
}
void DoClearMembers() {
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
m->~Member();
data_.o.size = 0;
}
void DoFreeMembers() {
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
m->~Member();
Allocator::Free(GetMembersPointer());
}
#endif // !RAPIDJSON_USE_MEMBERSMAP
void DoAddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
ObjectData& o = data_.o;
if (o.size >= o.capacity)
DoReserveMembers(o.capacity ? (o.capacity + (o.capacity + 1) / 2) : kDefaultObjectCapacity, allocator);
Member* members = GetMembersPointer();
Member* m = members + o.size;
m->name.RawAssign(name);
m->value.RawAssign(value);
#if RAPIDJSON_USE_MEMBERSMAP
Map* &map = GetMap(members);
MapIterator* mit = GetMapIterators(map);
new (&mit[o.size]) MapIterator(map->insert(MapPair(m->name.data_, o.size)));
#endif
++o.size;
}
MemberIterator DoRemoveMember(MemberIterator m) {
ObjectData& o = data_.o;
Member* members = GetMembersPointer();
#if RAPIDJSON_USE_MEMBERSMAP
Map* &map = GetMap(members);
MapIterator* mit = GetMapIterators(map);
SizeType mpos = static_cast<SizeType>(&*m - members);
map->erase(DropMapIterator(mit[mpos]));
#endif
MemberIterator last(members + (o.size - 1));
if (o.size > 1 && m != last) {
#if RAPIDJSON_USE_MEMBERSMAP
new (&mit[mpos]) MapIterator(DropMapIterator(mit[&*last - members]));
mit[mpos]->second = mpos;
#endif
*m = *last; // Move the last one to this place
}
else {
m->~Member(); // Only one left, just destroy
}
--o.size;
return m;
}
MemberIterator DoEraseMembers(ConstMemberIterator first, ConstMemberIterator last) {
ObjectData& o = data_.o;
MemberIterator beg = MemberBegin(),
pos = beg + (first - beg),
end = MemberEnd();
#if RAPIDJSON_USE_MEMBERSMAP
Map* &map = GetMap(GetMembersPointer());
MapIterator* mit = GetMapIterators(map);
#endif
for (MemberIterator itr = pos; itr != last; ++itr) {
#if RAPIDJSON_USE_MEMBERSMAP
map->erase(DropMapIterator(mit[itr - beg]));
#endif
itr->~Member();
}
#if RAPIDJSON_USE_MEMBERSMAP
if (first != last) {
// Move remaining members/iterators
MemberIterator next = pos + (last - first);
for (MemberIterator itr = pos; next != end; ++itr, ++next) {
std::memcpy(static_cast<void*>(&*itr), &*next, sizeof(Member));
SizeType mpos = static_cast<SizeType>(itr - beg);
new (&mit[mpos]) MapIterator(DropMapIterator(mit[next - beg]));
mit[mpos]->second = mpos;
}
}
#else
std::memmove(static_cast<void*>(&*pos), &*last,
static_cast<size_t>(end - last) * sizeof(Member));
#endif
o.size -= static_cast<SizeType>(last - first);
return pos;
}
template <typename SourceAllocator>
void DoCopyMembers(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings) {
RAPIDJSON_ASSERT(rhs.GetType() == kObjectType);
data_.f.flags = kObjectFlag;
SizeType count = rhs.data_.o.size;
Member* lm = DoAllocMembers(count, allocator);
const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();
#if RAPIDJSON_USE_MEMBERSMAP
Map* &map = GetMap(lm);
MapIterator* mit = GetMapIterators(map);
#endif
for (SizeType i = 0; i < count; i++) {
new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
#if RAPIDJSON_USE_MEMBERSMAP
new (&mit[i]) MapIterator(map->insert(MapPair(lm[i].name.data_, i)));
#endif
}
data_.o.size = data_.o.capacity = count;
SetMembersPointer(lm);
}
// Initialize this value as array with initial data, without calling destructor.
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
data_.f.flags = kArrayFlag;
if (count) {
GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
SetElementsPointer(e);
std::memcpy(static_cast<void*>(e), values, count * sizeof(GenericValue));
}
else
SetElementsPointer(0);
data_.a.size = data_.a.capacity = count;
}
//! Initialize this value as object with initial data, without calling destructor.
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
data_.f.flags = kObjectFlag;
if (count) {
Member* m = DoAllocMembers(count, allocator);
SetMembersPointer(m);
std::memcpy(static_cast<void*>(m), members, count * sizeof(Member));
#if RAPIDJSON_USE_MEMBERSMAP
Map* &map = GetMap(m);
MapIterator* mit = GetMapIterators(map);
for (SizeType i = 0; i < count; i++) {
new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i)));
}
#endif
}
else
SetMembersPointer(0);
data_.o.size = data_.o.capacity = count;
}
//! Initialize this value as constant string, without calling destructor.
void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
data_.f.flags = kConstStringFlag;
SetStringPointer(s);
data_.s.length = s.length;
}
//! Initialize this value as copy string with initial data, without calling destructor.
void SetStringRaw(StringRefType s, Allocator& allocator) {
Ch* str = 0;
if (ShortString::Usable(s.length)) {
data_.f.flags = kShortStringFlag;
data_.ss.SetLength(s.length);
str = data_.ss.str;
} else {
data_.f.flags = kCopyStringFlag;
data_.s.length = s.length;
str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));
SetStringPointer(str);
}
std::memcpy(str, s, s.length * sizeof(Ch));
str[s.length] = '\0';
}
//! Assignment without calling destructor
void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
data_ = rhs.data_;
// data_.f.flags = rhs.data_.f.flags;
rhs.data_.f.flags = kNullFlag;
}
template <typename SourceAllocator>
bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {
RAPIDJSON_ASSERT(IsString());
RAPIDJSON_ASSERT(rhs.IsString());
const SizeType len1 = GetStringLength();
const SizeType len2 = rhs.GetStringLength();
if(len1 != len2) { return false; }
const Ch* const str1 = GetString();
const Ch* const str2 = rhs.GetString();
if(str1 == str2) { return true; } // fast path for constant string
return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);
}
Data data_;
};
//! GenericValue with UTF8 encoding
typedef GenericValue<UTF8<> > Value;
///////////////////////////////////////////////////////////////////////////////
// GenericDocument
//! A document for parsing JSON text as DOM.
/*!
\note implements Handler concept
\tparam Encoding Encoding for both parsing and string storage.
\tparam Allocator Allocator for allocating memory for the DOM
\tparam StackAllocator Allocator for allocating memory for stack during parsing.
\warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
*/
template <typename Encoding, typename Allocator = RAPIDJSON_DEFAULT_ALLOCATOR, typename StackAllocator = RAPIDJSON_DEFAULT_STACK_ALLOCATOR >
class GenericDocument : public GenericValue<Encoding, Allocator> {
public:
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
//! Constructor
/*! Creates an empty document of specified type.
\param type Mandatory type of object to create.
\param allocator Optional allocator for allocating memory.
\param stackCapacity Optional initial capacity of stack in bytes.
\param stackAllocator Optional allocator for allocating memory for stack.
*/
explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
{
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
}
//! Constructor
/*! Creates an empty document which type is Null.
\param allocator Optional allocator for allocating memory.
\param stackCapacity Optional initial capacity of stack in bytes.
\param stackAllocator Optional allocator for allocating memory for stack.
*/
GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
{
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Move constructor in C++11
GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
: ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document
allocator_(rhs.allocator_),
ownAllocator_(rhs.ownAllocator_),
stack_(std::move(rhs.stack_)),
parseResult_(rhs.parseResult_)
{
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
rhs.parseResult_ = ParseResult();
}
#endif
~GenericDocument() {
// Clear the ::ValueType before ownAllocator is destroyed, ~ValueType()
// runs last and may access its elements or members which would be freed
// with an allocator like MemoryPoolAllocator (CrtAllocator does not
// free its data when destroyed, but MemoryPoolAllocator does).
if (ownAllocator_) {
ValueType::SetNull();
}
Destroy();
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Move assignment in C++11
GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
{
// The cast to ValueType is necessary here, because otherwise it would
// attempt to call GenericValue's templated assignment operator.
ValueType::operator=(std::forward<ValueType>(rhs));
// Calling the destructor here would prematurely call stack_'s destructor
Destroy();
allocator_ = rhs.allocator_;
ownAllocator_ = rhs.ownAllocator_;
stack_ = std::move(rhs.stack_);
parseResult_ = rhs.parseResult_;
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
rhs.parseResult_ = ParseResult();
return *this;
}
#endif
//! Exchange the contents of this document with those of another.
/*!
\param rhs Another document.
\note Constant complexity.
\see GenericValue::Swap
*/
GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {
ValueType::Swap(rhs);
stack_.Swap(rhs.stack_);
internal::Swap(allocator_, rhs.allocator_);
internal::Swap(ownAllocator_, rhs.ownAllocator_);
internal::Swap(parseResult_, rhs.parseResult_);
return *this;
}
// Allow Swap with ValueType.
// Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names.
using ValueType::Swap;
//! free-standing swap function helper
/*!
Helper function to enable support for common swap implementation pattern based on \c std::swap:
\code
void swap(MyClass& a, MyClass& b) {
using std::swap;
swap(a.doc, b.doc);
// ...
}
\endcode
\see Swap()
*/
friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
//! Populate this document by a generator which produces SAX events.
/*! \tparam Generator A functor with <tt>bool f(Handler)</tt> prototype.
\param g Generator functor which sends SAX events to the parameter.
\return The document itself for fluent API.
*/
template <typename Generator>
GenericDocument& Populate(Generator& g) {
ClearStackOnExit scope(*this);
if (g(*this)) {
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
}
return *this;
}
//!@name Parse from stream
//!@{
//! Parse JSON text from an input stream (with Encoding conversion)
/*! \tparam parseFlags Combination of \ref ParseFlag.
\tparam SourceEncoding Encoding of input stream
\tparam InputStream Type of input stream, implementing Stream concept
\param is Input stream to be parsed.
\return The document itself for fluent API.
*/
template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
GenericDocument& ParseStream(InputStream& is) {
GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
ClearStackOnExit scope(*this);
parseResult_ = reader.template Parse<parseFlags>(is, *this);
if (parseResult_) {
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
}
return *this;
}
//! Parse JSON text from an input stream
/*! \tparam parseFlags Combination of \ref ParseFlag.
\tparam InputStream Type of input stream, implementing Stream concept
\param is Input stream to be parsed.
\return The document itself for fluent API.
*/
template <unsigned parseFlags, typename InputStream>
GenericDocument& ParseStream(InputStream& is) {
return ParseStream<parseFlags, Encoding, InputStream>(is);
}
//! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
/*! \tparam InputStream Type of input stream, implementing Stream concept
\param is Input stream to be parsed.
\return The document itself for fluent API.
*/
template <typename InputStream>
GenericDocument& ParseStream(InputStream& is) {
return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
}
//!@}
//!@name Parse in-place from mutable string
//!@{
//! Parse JSON text from a mutable string
/*! \tparam parseFlags Combination of \ref ParseFlag.
\param str Mutable zero-terminated string to be parsed.
\return The document itself for fluent API.
*/
template <unsigned parseFlags>
GenericDocument& ParseInsitu(Ch* str) {
GenericInsituStringStream<Encoding> s(str);
return ParseStream<parseFlags | kParseInsituFlag>(s);
}
//! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
/*! \param str Mutable zero-terminated string to be parsed.
\return The document itself for fluent API.
*/
GenericDocument& ParseInsitu(Ch* str) {
return ParseInsitu<kParseDefaultFlags>(str);
}
//!@}
//!@name Parse from read-only string
//!@{
//! Parse JSON text from a read-only string (with Encoding conversion)
/*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
\tparam SourceEncoding Transcoding from input Encoding
\param str Read-only zero-terminated string to be parsed.
*/
template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& Parse(const typename SourceEncoding::Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<SourceEncoding> s(str);
return ParseStream<parseFlags, SourceEncoding>(s);
}
//! Parse JSON text from a read-only string
/*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
\param str Read-only zero-terminated string to be parsed.
*/
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
return Parse<parseFlags, Encoding>(str);
}
//! Parse JSON text from a read-only string (with \ref kParseDefaultFlags)
/*! \param str Read-only zero-terminated string to be parsed.
*/
GenericDocument& Parse(const Ch* str) {
return Parse<kParseDefaultFlags>(str);
}
template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
MemoryStream ms(reinterpret_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));
EncodedInputStream<SourceEncoding, MemoryStream> is(ms);
ParseStream<parseFlags, SourceEncoding>(is);
return *this;
}
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str, size_t length) {
return Parse<parseFlags, Encoding>(str, length);
}
GenericDocument& Parse(const Ch* str, size_t length) {
return Parse<kParseDefaultFlags>(str, length);
}
#if RAPIDJSON_HAS_STDSTRING
template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& Parse(const std::basic_string<typename SourceEncoding::Ch>& str) {
// c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t)
return Parse<parseFlags, SourceEncoding>(str.c_str());
}
template <unsigned parseFlags>
GenericDocument& Parse(const std::basic_string<Ch>& str) {
return Parse<parseFlags, Encoding>(str.c_str());
}
GenericDocument& Parse(const std::basic_string<Ch>& str) {
return Parse<kParseDefaultFlags>(str);
}
#endif // RAPIDJSON_HAS_STDSTRING
//!@}
//!@name Handling parse errors
//!@{
//! Whether a parse error has occurred in the last parsing.
bool HasParseError() const { return parseResult_.IsError(); }
//! Get the \ref ParseErrorCode of last parsing.
ParseErrorCode GetParseError() const { return parseResult_.Code(); }
//! Get the position of last parsing error in input, 0 otherwise.
size_t GetErrorOffset() const { return parseResult_.Offset(); }
//! Implicit conversion to get the last parse result
#ifndef __clang // -Wdocumentation
/*! \return \ref ParseResult of the last parse operation
\code
Document doc;
ParseResult ok = doc.Parse(json);
if (!ok)
printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset());
\endcode
*/
#endif
operator ParseResult() const { return parseResult_; }
//!@}
//! Get the allocator of this document.
Allocator& GetAllocator() {
RAPIDJSON_ASSERT(allocator_);
return *allocator_;
}
//! Get the capacity of stack in bytes.
size_t GetStackCapacity() const { return stack_.GetCapacity(); }
private:
// clear stack on any exit from ParseStream, e.g. due to exception
struct ClearStackOnExit {
explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}
~ClearStackOnExit() { d_.ClearStack(); }
private:
ClearStackOnExit(const ClearStackOnExit&);
ClearStackOnExit& operator=(const ClearStackOnExit&);
GenericDocument& d_;
};
// callers of the following private Handler functions
// template <typename,typename,typename> friend class GenericReader; // for parsing
template <typename, typename> friend class GenericValue; // for deep copying
public:
// Implementation of Handler
bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }
bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
bool RawNumber(const Ch* str, SizeType length, bool copy) {
if (copy)
new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
else
new (stack_.template Push<ValueType>()) ValueType(str, length);
return true;
}
bool String(const Ch* str, SizeType length, bool copy) {
if (copy)
new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
else
new (stack_.template Push<ValueType>()) ValueType(str, length);
return true;
}
bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }
bool EndObject(SizeType memberCount) {
typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator());
return true;
}
bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }
bool EndArray(SizeType elementCount) {
ValueType* elements = stack_.template Pop<ValueType>(elementCount);
stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
return true;
}
private:
//! Prohibit copying
GenericDocument(const GenericDocument&);
//! Prohibit assignment
GenericDocument& operator=(const GenericDocument&);
void ClearStack() {
if (Allocator::kNeedFree)
while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
(stack_.template Pop<ValueType>(1))->~ValueType();
else
stack_.Clear();
stack_.ShrinkToFit();
}
void Destroy() {
RAPIDJSON_DELETE(ownAllocator_);
}
static const size_t kDefaultStackCapacity = 1024;
Allocator* allocator_;
Allocator* ownAllocator_;
internal::Stack<StackAllocator> stack_;
ParseResult parseResult_;
};
//! GenericDocument with UTF8 encoding
typedef GenericDocument<UTF8<> > Document;
//! Helper class for accessing Value of array type.
/*!
Instance of this helper class is obtained by \c GenericValue::GetArray().
In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
*/
template <bool Const, typename ValueT>
class GenericArray {
public:
typedef GenericArray<true, ValueT> ConstArray;
typedef GenericArray<false, ValueT> Array;
typedef ValueT PlainType;
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
typedef ValueType* ValueIterator; // This may be const or non-const iterator
typedef const ValueT* ConstValueIterator;
typedef typename ValueType::AllocatorType AllocatorType;
typedef typename ValueType::StringRefType StringRefType;
template <typename, typename>
friend class GenericValue;
GenericArray(const GenericArray& rhs) : value_(rhs.value_) {}
GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }
~GenericArray() {}
operator ValueType&() const { return value_; }
SizeType Size() const { return value_.Size(); }
SizeType Capacity() const { return value_.Capacity(); }
bool Empty() const { return value_.Empty(); }
void Clear() const { value_.Clear(); }
ValueType& operator[](SizeType index) const { return value_[index]; }
ValueIterator Begin() const { return value_.Begin(); }
ValueIterator End() const { return value_.End(); }
GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; }
GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
GenericArray PopBack() const { value_.PopBack(); return *this; }
ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); }
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); }
#if RAPIDJSON_HAS_CXX11_RANGE_FOR
ValueIterator begin() const { return value_.Begin(); }
ValueIterator end() const { return value_.End(); }
#endif
private:
GenericArray();
GenericArray(ValueType& value) : value_(value) {}
ValueType& value_;
};
//! Helper class for accessing Value of object type.
/*!
Instance of this helper class is obtained by \c GenericValue::GetObject().
In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
*/
template <bool Const, typename ValueT>
class GenericObject {
public:
typedef GenericObject<true, ValueT> ConstObject;
typedef GenericObject<false, ValueT> Object;
typedef ValueT PlainType;
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
typedef GenericMemberIterator<Const, typename ValueT::EncodingType, typename ValueT::AllocatorType> MemberIterator; // This may be const or non-const iterator
typedef GenericMemberIterator<true, typename ValueT::EncodingType, typename ValueT::AllocatorType> ConstMemberIterator;
typedef typename ValueType::AllocatorType AllocatorType;
typedef typename ValueType::StringRefType StringRefType;
typedef typename ValueType::EncodingType EncodingType;
typedef typename ValueType::Ch Ch;
template <typename, typename>
friend class GenericValue;
GenericObject(const GenericObject& rhs) : value_(rhs.value_) {}
GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }
~GenericObject() {}
operator ValueType&() const { return value_; }
SizeType MemberCount() const { return value_.MemberCount(); }
SizeType MemberCapacity() const { return value_.MemberCapacity(); }
bool ObjectEmpty() const { return value_.ObjectEmpty(); }
template <typename T> ValueType& operator[](T* name) const { return value_[name]; }
template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }
#if RAPIDJSON_HAS_STDSTRING
ValueType& operator[](const std::basic_string<Ch>& name) const { return value_[name]; }
#endif
MemberIterator MemberBegin() const { return value_.MemberBegin(); }
MemberIterator MemberEnd() const { return value_.MemberEnd(); }
GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; }
bool HasMember(const Ch* name) const { return value_.HasMember(name); }
#if RAPIDJSON_HAS_STDSTRING
bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }
#endif
template <typename SourceAllocator> bool HasMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.HasMember(name); }
MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); }
template <typename SourceAllocator> MemberIterator FindMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.FindMember(name); }
#if RAPIDJSON_HAS_STDSTRING
MemberIterator FindMember(const std::basic_string<Ch>& name) const { return value_.FindMember(name); }
#endif
GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
#if RAPIDJSON_HAS_STDSTRING
GenericObject AddMember(ValueType& name, std::basic_string<Ch>& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
#endif
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
void RemoveAllMembers() { value_.RemoveAllMembers(); }
bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); }
#if RAPIDJSON_HAS_STDSTRING
bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); }
#endif
template <typename SourceAllocator> bool RemoveMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.RemoveMember(name); }
MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); }
MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); }
MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); }
bool EraseMember(const Ch* name) const { return value_.EraseMember(name); }
#if RAPIDJSON_HAS_STDSTRING
bool EraseMember(const std::basic_string<Ch>& name) const { return EraseMember(ValueType(StringRef(name))); }
#endif
template <typename SourceAllocator> bool EraseMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.EraseMember(name); }
#if RAPIDJSON_HAS_CXX11_RANGE_FOR
MemberIterator begin() const { return value_.MemberBegin(); }
MemberIterator end() const { return value_.MemberEnd(); }
#endif
private:
GenericObject();
GenericObject(ValueType& value) : value_(value) {}
ValueType& value_;
};
RAPIDJSON_NAMESPACE_END
RAPIDJSON_DIAG_POP
#ifdef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
#pragma pop_macro("GetObject")
#undef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
#endif
#endif // RAPIDJSON_DOCUMENT_H_
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
#define RAPIDJSON_ENCODEDSTREAM_H_
#include "stream.h"
#include "memorystream.h"
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Input byte stream wrapper with a statically bound encoding.
/*!
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
\tparam InputByteStream Type of input byte stream. For example, FileReadStream.
*/
template <typename Encoding, typename InputByteStream>
class EncodedInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public:
typedef typename Encoding::Ch Ch;
EncodedInputStream(InputByteStream& is) : is_(is) {
current_ = Encoding::TakeBOM(is_);
}
Ch Peek() const { return current_; }
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
size_t Tell() const { return is_.Tell(); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
EncodedInputStream(const EncodedInputStream&);
EncodedInputStream& operator=(const EncodedInputStream&);
InputByteStream& is_;
Ch current_;
};
//! Specialized for UTF8 MemoryStream.
template <>
class EncodedInputStream<UTF8<>, MemoryStream> {
public:
typedef UTF8<>::Ch Ch;
EncodedInputStream(MemoryStream& is) : is_(is) {
if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
}
Ch Peek() const { return is_.Peek(); }
Ch Take() { return is_.Take(); }
size_t Tell() const { return is_.Tell(); }
// Not implemented
void Put(Ch) {}
void Flush() {}
Ch* PutBegin() { return 0; }
size_t PutEnd(Ch*) { return 0; }
MemoryStream& is_;
private:
EncodedInputStream(const EncodedInputStream&);
EncodedInputStream& operator=(const EncodedInputStream&);
};
//! Output byte stream wrapper with statically bound encoding.
/*!
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
*/
template <typename Encoding, typename OutputByteStream>
class EncodedOutputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public:
typedef typename Encoding::Ch Ch;
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
if (putBOM)
Encoding::PutBOM(os_);
}
void Put(Ch c) { Encoding::Put(os_, c); }
void Flush() { os_.Flush(); }
// Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
EncodedOutputStream(const EncodedOutputStream&);
EncodedOutputStream& operator=(const EncodedOutputStream&);
OutputByteStream& os_;
};
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
\tparam CharType Type of character for reading.
\tparam InputByteStream type of input byte stream to be wrapped.
*/
template <typename CharType, typename InputByteStream>
class AutoUTFInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public:
typedef CharType Ch;
//! Constructor.
/*!
\param is input stream to be wrapped.
\param type UTF encoding type if it is not detected from the stream.
*/
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
DetectType();
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
takeFunc_ = f[type_];
current_ = takeFunc_(*is_);
}
UTFType GetType() const { return type_; }
bool HasBOM() const { return hasBOM_; }
Ch Peek() const { return current_; }
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
size_t Tell() const { return is_->Tell(); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
AutoUTFInputStream(const AutoUTFInputStream&);
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
// Detect encoding type with BOM or RFC 4627
void DetectType() {
// BOM (Byte Order Mark):
// 00 00 FE FF UTF-32BE
// FF FE 00 00 UTF-32LE
// FE FF UTF-16BE
// FF FE UTF-16LE
// EF BB BF UTF-8
const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
if (!c)
return;
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
hasBOM_ = false;
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
// RFC 4627: Section 3
// "Since the first two characters of a JSON text will always be ASCII
// characters [RFC0020], it is possible to determine whether an octet
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
// at the pattern of nulls in the first four octets."
// 00 00 00 xx UTF-32BE
// 00 xx 00 xx UTF-16BE
// xx 00 00 00 UTF-32LE
// xx 00 xx 00 UTF-16LE
// xx xx xx xx UTF-8
if (!hasBOM_) {
int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
switch (pattern) {
case 0x08: type_ = kUTF32BE; break;
case 0x0A: type_ = kUTF16BE; break;
case 0x01: type_ = kUTF32LE; break;
case 0x05: type_ = kUTF16LE; break;
case 0x0F: type_ = kUTF8; break;
default: break; // Use type defined by user.
}
}
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
}
typedef Ch (*TakeFunc)(InputByteStream& is);
InputByteStream* is_;
UTFType type_;
Ch current_;
TakeFunc takeFunc_;
bool hasBOM_;
};
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
\tparam CharType Type of character for writing.
\tparam OutputByteStream type of output byte stream to be wrapped.
*/
template <typename CharType, typename OutputByteStream>
class AutoUTFOutputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public:
typedef CharType Ch;
//! Constructor.
/*!
\param os output stream to be wrapped.
\param type UTF encoding type.
\param putBOM Whether to write BOM at the beginning of the stream.
*/
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
putFunc_ = f[type_];
if (putBOM)
PutBOM();
}
UTFType GetType() const { return type_; }
void Put(Ch c) { putFunc_(*os_, c); }
void Flush() { os_->Flush(); }
// Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
AutoUTFOutputStream(const AutoUTFOutputStream&);
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
void PutBOM() {
typedef void (*PutBOMFunc)(OutputByteStream&);
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
f[type_](*os_);
}
typedef void (*PutFunc)(OutputByteStream&, Ch);
OutputByteStream* os_;
UTFType type_;
PutFunc putFunc_;
};
#undef RAPIDJSON_ENCODINGS_FUNC
RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_FILESTREAM_H_
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ENCODINGS_H_
#define RAPIDJSON_ENCODINGS_H_
#include "rapidjson.h"
#if defined(_MSC_VER) && !defined(__clang__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
RAPIDJSON_DIAG_OFF(4702) // unreachable code
#elif defined(__GNUC__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_OFF(overflow)
#endif
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Encoding
/*! \class rapidjson::Encoding
\brief Concept for encoding of Unicode characters.
\code
concept Encoding {
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
//! \brief Encode a Unicode codepoint to an output stream.
//! \param os Output stream.
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint);
//! \brief Decode a Unicode codepoint from an input stream.
//! \param is Input stream.
//! \param codepoint Output of the unicode codepoint.
//! \return true if a valid codepoint can be decoded from the stream.
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint);
//! \brief Validate one Unicode codepoint from an encoded stream.
//! \param is Input stream to obtain codepoint.
//! \param os Output for copying one codepoint.
//! \return true if it is valid.
//! \note This function just validating and copying the codepoint without actually decode it.
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os);
// The following functions are deal with byte streams.
//! Take a character from input byte stream, skip BOM if exist.
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is);
//! Take a character from input byte stream.
template <typename InputByteStream>
static Ch Take(InputByteStream& is);
//! Put BOM to output byte stream.
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os);
//! Put a character to output byte stream.
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c);
};
\endcode
*/
///////////////////////////////////////////////////////////////////////////////
// UTF8
//! UTF-8 encoding.
/*! http://en.wikipedia.org/wiki/UTF-8
http://tools.ietf.org/html/rfc3629
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
\note implements Encoding concept
*/
template<typename CharType = char>
struct UTF8 {
typedef CharType Ch;
enum { supportUnicode = 1 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
if (codepoint <= 0x7F)
os.Put(static_cast<Ch>(codepoint & 0xFF));
else if (codepoint <= 0x7FF) {
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
}
else if (codepoint <= 0xFFFF) {
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
}
else {
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
}
}
template<typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
if (codepoint <= 0x7F)
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
else if (codepoint <= 0x7FF) {
PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
}
else if (codepoint <= 0xFFFF) {
PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
}
else {
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
}
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
typename InputStream::Ch c = is.Take();
if (!(c & 0x80)) {
*codepoint = static_cast<unsigned char>(c);
return true;
}
unsigned char type = GetRange(static_cast<unsigned char>(c));
if (type >= 32) {
*codepoint = 0;
} else {
*codepoint = (0xFFu >> type) & static_cast<unsigned char>(c);
}
bool result = true;
switch (type) {
case 2: RAPIDJSON_TAIL(); return result;
case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
default: return false;
}
#undef RAPIDJSON_COPY
#undef RAPIDJSON_TRANS
#undef RAPIDJSON_TAIL
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
#define RAPIDJSON_COPY() os.Put(c = is.Take())
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
Ch c;
RAPIDJSON_COPY();
if (!(c & 0x80))
return true;
bool result = true;
switch (GetRange(static_cast<unsigned char>(c))) {
case 2: RAPIDJSON_TAIL(); return result;
case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
default: return false;
}
#undef RAPIDJSON_COPY
#undef RAPIDJSON_TRANS
#undef RAPIDJSON_TAIL
}
static unsigned char GetRange(unsigned char c) {
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
static const unsigned char type[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
};
return type[c];
}
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
typename InputByteStream::Ch c = Take(is);
if (static_cast<unsigned char>(c) != 0xEFu) return c;
c = is.Take();
if (static_cast<unsigned char>(c) != 0xBBu) return c;
c = is.Take();
if (static_cast<unsigned char>(c) != 0xBFu) return c;
c = is.Take();
return c;
}
template <typename InputByteStream>
static Ch Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return static_cast<Ch>(is.Take());
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(c));
}
};
///////////////////////////////////////////////////////////////////////////////
// UTF16
//! UTF-16 encoding.
/*! http://en.wikipedia.org/wiki/UTF-16
http://tools.ietf.org/html/rfc2781
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
\note implements Encoding concept
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF16LE and UTF16BE, which handle endianness.
*/
template<typename CharType = wchar_t>
struct UTF16 {
typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
enum { supportUnicode = 1 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
if (codepoint <= 0xFFFF) {
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
os.Put(static_cast<typename OutputStream::Ch>(codepoint));
}
else {
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000;
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
}
}
template<typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
if (codepoint <= 0xFFFF) {
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
}
else {
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000;
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
}
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
typename InputStream::Ch c = is.Take();
if (c < 0xD800 || c > 0xDFFF) {
*codepoint = static_cast<unsigned>(c);
return true;
}
else if (c <= 0xDBFF) {
*codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
c = is.Take();
*codepoint |= (static_cast<unsigned>(c) & 0x3FF);
*codepoint += 0x10000;
return c >= 0xDC00 && c <= 0xDFFF;
}
return false;
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
typename InputStream::Ch c;
os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
if (c < 0xD800 || c > 0xDFFF)
return true;
else if (c <= 0xDBFF) {
os.Put(c = is.Take());
return c >= 0xDC00 && c <= 0xDFFF;
}
return false;
}
};
//! UTF-16 little endian encoding.
template<typename CharType = wchar_t>
struct UTF16LE : UTF16<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
unsigned c = static_cast<uint8_t>(is.Take());
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
return static_cast<CharType>(c);
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
}
};
//! UTF-16 big endian encoding.
template<typename CharType = wchar_t>
struct UTF16BE : UTF16<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
return static_cast<CharType>(c);
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
}
};
///////////////////////////////////////////////////////////////////////////////
// UTF32
//! UTF-32 encoding.
/*! http://en.wikipedia.org/wiki/UTF-32
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
\note implements Encoding concept
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF32LE and UTF32BE, which handle endianness.
*/
template<typename CharType = unsigned>
struct UTF32 {
typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
enum { supportUnicode = 1 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(codepoint);
}
template<typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
PutUnsafe(os, codepoint);
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
Ch c = is.Take();
*codepoint = c;
return c <= 0x10FFFF;
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
Ch c;
os.Put(c = is.Take());
return c <= 0x10FFFF;
}
};
//! UTF-32 little endian enocoding.
template<typename CharType = unsigned>
struct UTF32LE : UTF32<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
unsigned c = static_cast<uint8_t>(is.Take());
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
return static_cast<CharType>(c);
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
}
};
//! UTF-32 big endian encoding.
template<typename CharType = unsigned>
struct UTF32BE : UTF32<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
return static_cast<CharType>(c);
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
}
};
///////////////////////////////////////////////////////////////////////////////
// ASCII
//! ASCII encoding.
/*! http://en.wikipedia.org/wiki/ASCII
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
\note implements Encoding concept
*/
template<typename CharType = char>
struct ASCII {
typedef CharType Ch;
enum { supportUnicode = 0 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_ASSERT(codepoint <= 0x7F);
os.Put(static_cast<Ch>(codepoint & 0xFF));
}
template<typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
RAPIDJSON_ASSERT(codepoint <= 0x7F);
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
uint8_t c = static_cast<uint8_t>(is.Take());
*codepoint = c;
return c <= 0X7F;
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
uint8_t c = static_cast<uint8_t>(is.Take());
os.Put(static_cast<typename OutputStream::Ch>(c));
return c <= 0x7F;
}
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
uint8_t c = static_cast<uint8_t>(Take(is));
return static_cast<Ch>(c);
}
template <typename InputByteStream>
static Ch Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return static_cast<Ch>(is.Take());
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
(void)os;
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(c));
}
};
///////////////////////////////////////////////////////////////////////////////
// AutoUTF
//! Runtime-specified UTF encoding type of a stream.
enum UTFType {
kUTF8 = 0, //!< UTF-8.
kUTF16LE = 1, //!< UTF-16 little endian.
kUTF16BE = 2, //!< UTF-16 big endian.
kUTF32LE = 3, //!< UTF-32 little endian.
kUTF32BE = 4 //!< UTF-32 big endian.
};
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
*/
template<typename CharType>
struct AutoUTF {
typedef CharType Ch;
enum { supportUnicode = 1 };
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
template<typename OutputStream>
static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) {
typedef void (*EncodeFunc)(OutputStream&, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
(*f[os.GetType()])(os, codepoint);
}
template<typename OutputStream>
static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
typedef void (*EncodeFunc)(OutputStream&, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
(*f[os.GetType()])(os, codepoint);
}
template <typename InputStream>
static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) {
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
return (*f[is.GetType()])(is, codepoint);
}
template <typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
return (*f[is.GetType()])(is, os);
}
#undef RAPIDJSON_ENCODINGS_FUNC
};
///////////////////////////////////////////////////////////////////////////////
// Transcoder
//! Encoding conversion.
template<typename SourceEncoding, typename TargetEncoding>
struct Transcoder {
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
template<typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint))
return false;
TargetEncoding::Encode(os, codepoint);
return true;
}
template<typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint))
return false;
TargetEncoding::EncodeUnsafe(os, codepoint);
return true;
}
//! Validate one Unicode codepoint from an encoded stream.
template<typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
return Transcode(is, os); // Since source/target encoding is different, must transcode.
}
};
// Forward declaration.
template<typename Stream>
inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
//! Specialization of Transcoder with same source and target encoding.
template<typename Encoding>
struct Transcoder<Encoding, Encoding> {
template<typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true;
}
template<typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true;
}
template<typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
return Encoding::Validate(is, os); // source/target encoding are the same
}
};
RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__))
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_ENCODINGS_H_
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_EN_H_
#define RAPIDJSON_ERROR_EN_H_
#include "error.h"
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(switch-enum)
RAPIDJSON_DIAG_OFF(covered-switch-default)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Maps error code of parsing into error message.
/*!
\ingroup RAPIDJSON_ERRORS
\param parseErrorCode Error code obtained in parsing.
\return the error message.
\note User can make a copy of this function for localization.
Using switch-case is safer for future modification of error codes.
*/
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
switch (parseErrorCode) {
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
}
}
//! Maps error code of validation into error message.
/*!
\ingroup RAPIDJSON_ERRORS
\param validateErrorCode Error code obtained from validator.
\return the error message.
\note User can make a copy of this function for localization.
Using switch-case is safer for future modification of error codes.
*/
inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) {
switch (validateErrorCode) {
case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred");
case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'.");
case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'.");
case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'.");
case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'.");
case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'.");
case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'.");
case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'.");
case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression.");
case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'.");
case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'.");
case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true.");
case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema.");
case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'.");
case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'.");
case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'.");
case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema.");
case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema.");
case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors.");
case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values.");
case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'.");
case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors.");
case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'.");
case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors.");
case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
}
}
RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_ERROR_EN_H_
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_ERROR_H_
#define RAPIDJSON_ERROR_ERROR_H_
#include "../rapidjson.h"
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
/*! \file error.h */
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ERROR_CHARTYPE
//! Character type of error messages.
/*! \ingroup RAPIDJSON_ERRORS
The default character type is \c char.
On Windows, user can define this macro as \c TCHAR for supporting both
unicode/non-unicode settings.
*/
#ifndef RAPIDJSON_ERROR_CHARTYPE
#define RAPIDJSON_ERROR_CHARTYPE char
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ERROR_STRING
//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
/*! \ingroup RAPIDJSON_ERRORS
By default this conversion macro does nothing.
On Windows, user can define this macro as \c _T(x) for supporting both
unicode/non-unicode settings.
*/
#ifndef RAPIDJSON_ERROR_STRING
#define RAPIDJSON_ERROR_STRING(x) x
#endif
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// ParseErrorCode
//! Error code of parsing.
/*! \ingroup RAPIDJSON_ERRORS
\see GenericReader::Parse, GenericReader::GetParseErrorCode
*/
enum ParseErrorCode {
kParseErrorNone = 0, //!< No error.
kParseErrorDocumentEmpty, //!< The document is empty.
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
kParseErrorValueInvalid, //!< Invalid value.
kParseErrorObjectMissName, //!< Missing a name for object member.
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
kParseErrorNumberTooBig, //!< Number too big to be stored in double.
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
kParseErrorNumberMissExponent, //!< Miss exponent in number.
kParseErrorTermination, //!< Parsing was terminated.
kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
};
//! Result of parsing (wraps ParseErrorCode)
/*!
\ingroup RAPIDJSON_ERRORS
\code
Document doc;
ParseResult ok = doc.Parse("[42]");
if (!ok) {
fprintf(stderr, "JSON parse error: %s (%u)",
GetParseError_En(ok.Code()), ok.Offset());
exit(EXIT_FAILURE);
}
\endcode
\see GenericReader::Parse, GenericDocument::Parse
*/
struct ParseResult {
//!! Unspecified boolean type
typedef bool (ParseResult::*BooleanType)() const;
public:
//! Default constructor, no error.
ParseResult() : code_(kParseErrorNone), offset_(0) {}
//! Constructor to set an error.
ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
//! Get the error code.
ParseErrorCode Code() const { return code_; }
//! Get the error offset, if \ref IsError(), 0 otherwise.
size_t Offset() const { return offset_; }
//! Explicit conversion to \c bool, returns \c true, iff !\ref IsError().
operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
//! Whether the result is an error.
bool IsError() const { return code_ != kParseErrorNone; }
bool operator==(const ParseResult& that) const { return code_ == that.code_; }
bool operator==(ParseErrorCode code) const { return code_ == code; }
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
bool operator!=(const ParseResult& that) const { return !(*this == that); }
bool operator!=(ParseErrorCode code) const { return !(*this == code); }
friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; }
//! Reset error code.
void Clear() { Set(kParseErrorNone); }
//! Update error code and offset.
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
private:
ParseErrorCode code_;
size_t offset_;
};
//! Function pointer type of GetParseError().
/*! \ingroup RAPIDJSON_ERRORS
This is the prototype for \c GetParseError_X(), where \c X is a locale.
User can dynamically change locale in runtime, e.g.:
\code
GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
\endcode
*/
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
///////////////////////////////////////////////////////////////////////////////
// ValidateErrorCode
//! Error codes when validating.
/*! \ingroup RAPIDJSON_ERRORS
\see GenericSchemaValidator
*/
enum ValidateErrorCode {
kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set.
kValidateErrorNone = 0, //!< No error.
kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value.
kValidateErrorMaximum, //!< Number is greater than the 'maximum' value.
kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value.
kValidateErrorMinimum, //!< Number is less than the 'minimum' value.
kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value.
kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value.
kValidateErrorMinLength, //!< String is longer than the 'maxLength' value.
kValidateErrorPattern, //!< String does not match the 'pattern' regular expression.
kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value.
kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value.
kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true.
kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema.
kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value.
kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value.
kValidateErrorRequired, //!< Object is missing one or more members required by the schema.
kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema.
kValidateErrorPatternProperties, //!< See other errors.
kValidateErrorDependencies, //!< Object has missing property or schema dependencies.
kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values
kValidateErrorType, //!< Property has a type that is not allowed by the schema..
kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'.
kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'.
kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'.
kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'.
kValidateErrorNot //!< Property matched the sub-schema specified by 'not'.
};
//! Function pointer type of GetValidateError().
/*! \ingroup RAPIDJSON_ERRORS
This is the prototype for \c GetValidateError_X(), where \c X is a locale.
User can dynamically change locale in runtime, e.g.:
\code
GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever
const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode());
\endcode
*/
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode);
RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_ERROR_ERROR_H_
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEREADSTREAM_H_
#define RAPIDJSON_FILEREADSTREAM_H_
#include "stream.h"
#include <cstdio>
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(unreachable-code)
RAPIDJSON_DIAG_OFF(missing-noreturn)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! File byte stream for input using fread().
/*!
\note implements Stream concept
*/
class FileReadStream {
public:
typedef char Ch; //!< Character type (byte).
//! Constructor.
/*!
\param fp File pointer opened for read.
\param buffer user-supplied buffer.
\param bufferSize size of buffer in bytes. Must >=4 bytes.
*/
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
RAPIDJSON_ASSERT(fp_ != 0);
RAPIDJSON_ASSERT(bufferSize >= 4);
Read();
}
Ch Peek() const { return *current_; }
Ch Take() { Ch c = *current_; Read(); return c; }
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only.
const Ch* Peek4() const {
return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
}
private:
void Read() {
if (current_ < bufferLast_)
++current_;
else if (!eof_) {
count_ += readCount_;
readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
bufferLast_ = buffer_ + readCount_ - 1;
current_ = buffer_;
if (readCount_ < bufferSize_) {
buffer_[readCount_] = '\0';
++bufferLast_;
eof_ = true;
}
}
}
std::FILE* fp_;
Ch *buffer_;
size_t bufferSize_;
Ch *bufferLast_;
Ch *current_;
size_t readCount_;
size_t count_; //!< Number of characters read
bool eof_;
};
RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_FILESTREAM_H_
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
#define RAPIDJSON_FILEWRITESTREAM_H_
#include "stream.h"
#include <cstdio>
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(unreachable-code)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of C file stream for output using fwrite().
/*!
\note implements Stream concept
*/
class FileWriteStream {
public:
typedef char Ch; //!< Character type. Only support char.
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
RAPIDJSON_ASSERT(fp_ != 0);
}
void Put(char c) {
if (current_ >= bufferEnd_)
Flush();
*current_++ = c;
}
void PutN(char c, size_t n) {
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
while (n > avail) {
std::memset(current_, c, avail);
current_ += avail;
Flush();
n -= avail;
avail = static_cast<size_t>(bufferEnd_ - current_);
}
if (n > 0) {
std::memset(current_, c, n);
current_ += n;
}
}
void Flush() {
if (current_ != buffer_) {
size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
if (result < static_cast<size_t>(current_ - buffer_)) {
// failure deliberately ignored at this time
// added to avoid warn_unused_result build errors
}
current_ = buffer_;
}
}
// Not implemented
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
char Take() { RAPIDJSON_ASSERT(false); return 0; }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
private:
// Prohibit copy constructor & assignment operator.
FileWriteStream(const FileWriteStream&);
FileWriteStream& operator=(const FileWriteStream&);
std::FILE* fp_;
char *buffer_;
char *bufferEnd_;
char *current_;
};
//! Implement specialized version of PutN() with memset() for better performance.
template<>
inline void PutN(FileWriteStream& stream, char c, size_t n) {
stream.PutN(c, n);
}
RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_FILESTREAM_H_