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 6287 additions and 3755 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-backend.h
*
* \brief Header file for abstract backend participant implementation
* (used in the core library and as a base to derive specific backends).
*
* Users should not include this file directly, but use ipaaca.h
*
* \b Note: This file is only included during compilation of ipaaca,
* for regular use, the full internal API is not exposed.
* Users generally need never touch the internal transport layer.
*
* \author Ramin Yaghoubzadeh Torky (ryaghoubzadeh@uni-bielefeld.de)
* \date December, 2018
*/
#ifndef __ipaaca_backend_h_INCLUDED__
#define __ipaaca_backend_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
namespace backend {
#if _WIN32 || _WIN64
inline std::string generate_client_id()
{
// '-' not allowed e.g. in ROS
std::string uuid = ipaaca::generate_uuid_string().substr(0,8);
return uuid;
}
#else
// get simplified basename of the process name from /proc
// (we could also decide to route argv here instead)
inline std::string get_simplified_process_name()
{
std::fstream fs;
fs.open("/proc/self/cmdline", std::fstream::in);
if (!fs.is_open()) {
IPAACA_DEBUG("Could not open /proc/self/cmdline")
return "ipaaca_cpp";
}
std::string line;
std::vector<std::string> tokens;
if (!std::getline(fs, line)) {
IPAACA_DEBUG("Failed to read a line from /proc/self/cmdline")
fs.close();
return "ipaaca_cpp";
}
fs.close();
int cnt = ipaaca::str_split_append(line, tokens, "\000");
if (cnt < 1) {
IPAACA_DEBUG("Failed to get process name from /proc/self/cmdline")
return "ipaaca_cpp";
}
line = tokens[0];
cnt = ipaaca::str_split_wipe(line, tokens, "/");
if (cnt < 1) {
IPAACA_DEBUG("Failed to parse process name in /proc/self/cmdline")
return "ipaaca_cpp";
}
std::string procname;
line = tokens[cnt-1];
for (auto ch: line) {
if ((ch>='a' && ch<='z') || (ch>='A' && ch<='Z') || (ch>='0' && ch<='9') || (ch=='_')) {
procname += ch;
} else if (ch=='-' || ch=='.' || ch==' ') {
procname += '_';
}
}
if (procname=="") {
IPAACA_DEBUG("Only unacceptable characters in process name from /proc/self/cmdline")
return "ipaaca_cpp";
} else {
return procname;
}
}
inline std::string generate_client_id()
{
//std::stringstream ss;
//ss << "Process_" << getpid() << "_ClientID_" << ipaaca::generate_uuid_string();
//return ss.str();
std::string uuid = get_simplified_process_name() + "_" + ipaaca::generate_uuid_string().substr(0,8);
return uuid;
}
#endif
/*
* class Scope {
public:
std::string scope_string;
Scope(const std::string& sc): scope_string(sc) {}
Scope(const Scope& scope): scope_string(scope.scope_string) {}
inline operator std::string() const { return scope_string; }
};
*/
// RSB-like wrapper for {wire type; void ref to deserialized obj}
// to avoid modifying the event handling side.
class Event {
public:
typedef std::shared_ptr<Event> ptr;
protected:
std::string _type;
std::shared_ptr<void> _data;
public:
inline Event(const std::string& type, std::shared_ptr<void> data): _type(type), _data(data) { }
inline std::string getType() const { return _type; }
inline std::shared_ptr<void> getData() const { return _data; }
};
class PendingRequest {
/** Encapsulation of a pending remote request with
a facility to keep the requesting thread locked
until the reply or a timeout unlocks it. */
public:
typedef std::shared_ptr<PendingRequest> ptr;
protected:
Event::ptr _pending_request;
std::condition_variable _condvar;
std::mutex _condvar_mutex;
// block var
public:
std::string _request_uid;
int _result;
public:
inline PendingRequest(Event::ptr req) {
std::string uuid = ipaaca::generate_uuid_string();
_request_uid = uuid.substr(0,8);
_pending_request = req;
_result = -1;
}
/// reply_with_result is called by the backend when a remote request reply has been received (and it was a known tracked request)
inline void reply_with_result(int result) {
_result = result;
_condvar.notify_one(); // wake up the waiting thread
};
/// wait_for_reply is called internally by the user thread that attempts to modify remote IUs, it waits until the remote end replies
inline int wait_for_reply(long timeout_milliseconds = 30000) {
std::unique_lock<std::mutex> lock(_condvar_mutex);
// the remote end will set the result >=0 (from the other thread), which suffices to continue
auto success = _condvar.wait_for(lock, std::chrono::milliseconds(timeout_milliseconds), [this]{return this->_result >= 0;});
if (!success) {
IPAACA_ERROR("Request timeout: we did not receive a reply for a remote server request")
// TODO could throw instead
}
return _result;
}
};
//
// Abstract interface
//
class Informer {
public:
typedef std::shared_ptr<Informer> ptr;
protected:
std::string _client_id;
public:
IPAACA_HEADER_EXPORT inline virtual ~Informer() { }
template<typename Data> IPAACA_HEADER_EXPORT inline bool publish(Data d) { return internal_publish(ipaaca::converters::internal_serialize(d)); }
public:
//
// You MUST override these functions in the backend versions:
//
IPAACA_HEADER_EXPORT virtual bool internal_publish(const std::string& wire) { IPAACA_ERROR("Attempt to invoke abstract version of Informer::internal_publish"); throw NotImplementedError(); }
};
/*
IPAACA_HEADER_EXPORT virtual bool publish(ipaaca::IU::ptr) = 0;
IPAACA_HEADER_EXPORT virtual bool publish(ipaaca::Message::ptr) = 0;
IPAACA_HEADER_EXPORT virtual bool publish(ipaaca::IUPayloadUpdate::ptr) = 0;
IPAACA_HEADER_EXPORT virtual bool publish(ipaaca::IULinkUpdate::ptr) = 0;
IPAACA_HEADER_EXPORT virtual bool publish(std::shared_ptr<protobuf::RemoteRequestResult>) = 0;
IPAACA_HEADER_EXPORT virtual bool publish(std::shared_ptr<protobuf::IURetraction>) = 0;
IPAACA_HEADER_EXPORT virtual bool publish(std::shared_ptr<protobuf::IUCommission>) = 0;
IPAACA_HEADER_EXPORT virtual bool publish(std::shared_ptr<protobuf::IUResendRequest>) = 0;
IPAACA_HEADER_EXPORT virtual bool publish(std::shared_ptr<protobuf::IUPayloadUpdateRequest>) = 0;
IPAACA_HEADER_EXPORT virtual bool publish(std::shared_ptr<protobuf::IULinkUpdateRequest>) = 0;
IPAACA_HEADER_EXPORT virtual bool publish(std::shared_ptr<protobuf::IUCommissionRequest>
*/
class Listener {
public:
typedef std::shared_ptr<Listener> ptr;
protected:
ipaaca::InputBuffer* _buffer;
protected:
Listener(ipaaca::InputBuffer* buffer): _buffer(buffer) { }
public:
IPAACA_HEADER_EXPORT inline virtual ~Listener() { }
//inline Listener(const Scope& scope, InputBuffer* buffer_ptr, Config::ptr config = nullptr)) {}
void relay_received_event_to_buffer(Event::ptr event);
void relay_received_event_to_buffer_threaded(Event::ptr event);
};
class LocalServer {
public:
typedef std::shared_ptr<LocalServer> ptr;
protected:
ipaaca::OutputBuffer* _buffer;
protected:
LocalServer(ipaaca::OutputBuffer* buffer): _buffer(buffer) { }
public:
//inline LocalServer(const Scope& scope, ipaaca::OutputBuffer* buffer_ptr, Config::ptr config = nullptr): _buffer(buffer_ptr);
IPAACA_HEADER_EXPORT inline virtual ~LocalServer() { }
//IPAACA_HEADER_EXPORT virtual int64_t attempt_to_apply_remote_payload_update(std::shared_ptr<IUPayloadUpdate> update) = 0;
//IPAACA_HEADER_EXPORT virtual int64_t attempt_to_apply_remote_link_update(std::shared_ptr<IULinkUpdate> update) = 0;
//IPAACA_HEADER_EXPORT virtual int64_t attempt_to_apply_remote_commission(std::shared_ptr<protobuf::IUCommission> update) = 0;
//IPAACA_HEADER_EXPORT virtual int64_t attempt_to_apply_remote_resend_request(std::shared_ptr<protobuf::IUResendRequest> update) = 0;
IPAACA_HEADER_EXPORT int64_t attempt_to_apply_remote_payload_update(std::shared_ptr<IUPayloadUpdate> update);
IPAACA_HEADER_EXPORT int64_t attempt_to_apply_remote_link_update(std::shared_ptr<IULinkUpdate> update);
IPAACA_HEADER_EXPORT int64_t attempt_to_apply_remote_commission(std::shared_ptr<protobuf::IUCommission> update);
IPAACA_HEADER_EXPORT int64_t attempt_to_apply_remote_resend_request(std::shared_ptr<protobuf::IUResendRequest> update);
};
class RemoteServer {
public:
typedef std::shared_ptr<RemoteServer> ptr;
public:
//inline RemoteServer(const Scope& scope, Config::ptr config = nullptr) {
//}
IPAACA_HEADER_EXPORT inline virtual ~RemoteServer() { }
IPAACA_HEADER_EXPORT virtual int64_t request_remote_payload_update(std::shared_ptr<IUPayloadUpdate> update) = 0;
IPAACA_HEADER_EXPORT virtual int64_t request_remote_link_update(std::shared_ptr<IULinkUpdate> update) = 0;
IPAACA_HEADER_EXPORT virtual int64_t request_remote_commission(std::shared_ptr<protobuf::IUCommission> update) = 0;
IPAACA_HEADER_EXPORT virtual int64_t request_remote_resend_request(std::shared_ptr<protobuf::IUResendRequest> update) = 0;
};
class BackEnd {
public:
typedef std::shared_ptr<BackEnd> ptr;
protected:
std::string _backend_name;
public:
BackEnd(std::string backend_name): _backend_name(backend_name) { }
inline std::string name() const { return _backend_name; }
virtual ~BackEnd() {}
virtual void teardown() = 0;
virtual LocalServer::ptr createLocalServer(const std::string& scope, OutputBuffer* buf) = 0;
virtual Informer::ptr createInformer(const std::string& scope) = 0;
virtual RemoteServer::ptr createRemoteServer(const std::string& scope) = 0;
virtual Listener::ptr createListener(const std::string& scope, InputBuffer* buf) = 0;
virtual std::string make_valid_scope(const std::string& scope) = 0;
};
class BackEndLibrary {
public:
typedef std::shared_ptr<BackEndLibrary> ptr;
protected:
std::map<std::string, BackEnd::ptr> _backends;
public:
BackEndLibrary() { }
inline static BackEndLibrary::ptr get() {
static BackEndLibrary::ptr lib;
if (!lib) {
lib = std::make_shared<BackEndLibrary>();
}
return lib;
}
inline bool register_backend(BackEnd::ptr backend) {
if (_backends.count(backend->name())) {
IPAACA_ERROR("Not registering another BackEnd with already known name: " << backend->name())
return false;
} else {
_backends[backend->name()] = backend;
return true;
}
}
inline BackEnd::ptr get_default_backend() {
static BackEnd::ptr _singleton;
if (_singleton) return _singleton;
if (_backends.size() == 0) {
IPAACA_ERROR("No backends are registered inside the library - cannot continue")
throw BackEndNotFoundError();
}
std::string preferred_backend = get_global_config()->get_with_default<std::string>("backend", "");
if (preferred_backend != "") {
if (_backends.count(preferred_backend)) {
_singleton = _backends[preferred_backend];
} else {
IPAACA_ERROR("Failed to initialize the selected BackEnd " << preferred_backend)
throw BackEndNotFoundError();
}
} else {
// just return the first value // FIXME config or clean precedence rule
for (auto kv: _backends) {
IPAACA_WARNING("No 'backend' config found, selecting BackEnd " << kv.second->name())
_singleton = kv.second;
break;
}
}
if (_singleton) return _singleton;
throw BackEndNotFoundError(); // should not be reached; silence warnings
}
};
inline BackEnd::ptr get_default_backend() {
return BackEndLibrary::get()->get_default_backend();
}
} // of namespace backend
#endif
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -38,13 +38,17 @@ ...@@ -38,13 +38,17 @@
#error "Please do not include this file directly, use ipaaca.h instead" #error "Please do not include this file directly, use ipaaca.h instead"
#endif #endif
// Convenience macro to abstract from the bind implementation being used
// and possible future signature changes.
#define IPAACA_BIND_CLASS_HANDLER(fn, inst) std::bind(fn, inst, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)
/// Store for local IUs (used in OutputBuffer) /// Store for local IUs (used in OutputBuffer)
IPAACA_HEADER_EXPORT class IUStore: public std::map<std::string, boost::shared_ptr<IU> > class IUStore: public std::map<std::string, std::shared_ptr<IU> >
{ {
}; };
/// Store for RemotePushIUs (used in InputBuffer) /// Store for RemotePushIUs (used in InputBuffer)
IPAACA_HEADER_EXPORT class RemotePushIUStore: public std::map<std::string, boost::shared_ptr<RemotePushIU> > // TODO genericize to all remote IU types class RemotePushIUStore: public std::map<std::string, std::shared_ptr<RemotePushIU> >
{ {
}; };
...@@ -52,12 +56,12 @@ typedef std::set<std::string> LinkSet; ...@@ -52,12 +56,12 @@ typedef std::set<std::string> LinkSet;
typedef std::map<std::string, LinkSet> LinkMap; typedef std::map<std::string, LinkSet> LinkMap;
/// Container for IU links that gracefully returns the empty set if required /// Container for IU links that gracefully returns the empty set if required
IPAACA_HEADER_EXPORT class SmartLinkMap {//{{{ class SmartLinkMap {//{{{
friend std::ostream& operator<<(std::ostream& os, const SmartLinkMap& obj); friend std::ostream& operator<<(std::ostream& os, const SmartLinkMap& obj);
friend class IUInterface; friend class IUInterface;
friend class IU; friend class IU;
friend class IUConverter; friend class ipaaca::converters::IUConverter;
friend class MessageConverter; //friend class ipaaca::converters::MessageConverter;
public: public:
IPAACA_HEADER_EXPORT const LinkSet& get_links(const std::string& key); IPAACA_HEADER_EXPORT const LinkSet& get_links(const std::string& key);
IPAACA_HEADER_EXPORT const LinkMap& get_all_links(); IPAACA_HEADER_EXPORT const LinkMap& get_all_links();
...@@ -66,6 +70,7 @@ IPAACA_HEADER_EXPORT class SmartLinkMap {//{{{ ...@@ -66,6 +70,7 @@ IPAACA_HEADER_EXPORT class SmartLinkMap {//{{{
IPAACA_MEMBER_VAR_EXPORT LinkMap _links; IPAACA_MEMBER_VAR_EXPORT LinkMap _links;
/// The empty link set is returned if undefined links are read for an IU. /// The empty link set is returned if undefined links are read for an IU.
IPAACA_MEMBER_VAR_EXPORT static LinkSet empty_link_set; IPAACA_MEMBER_VAR_EXPORT static LinkSet empty_link_set;
protected:
IPAACA_HEADER_EXPORT void _add_and_remove_links(const LinkMap& add, const LinkMap& remove); IPAACA_HEADER_EXPORT void _add_and_remove_links(const LinkMap& add, const LinkMap& remove);
IPAACA_HEADER_EXPORT void _replace_links(const LinkMap& links); IPAACA_HEADER_EXPORT void _replace_links(const LinkMap& links);
};//}}} };//}}}
...@@ -74,7 +79,7 @@ IPAACA_HEADER_EXPORT class SmartLinkMap {//{{{ ...@@ -74,7 +79,7 @@ IPAACA_HEADER_EXPORT class SmartLinkMap {//{{{
IPAACA_MEMBER_VAR_EXPORT const LinkSet EMPTY_LINK_SET; IPAACA_MEMBER_VAR_EXPORT const LinkSet EMPTY_LINK_SET;
/// Configuration object that can be passed to Buffer constructors. /// Configuration object that can be passed to Buffer constructors.
IPAACA_HEADER_EXPORT class BufferConfiguration//{{{ class BufferConfiguration//{{{
{ {
protected: protected:
IPAACA_MEMBER_VAR_EXPORT std::string _basename; IPAACA_MEMBER_VAR_EXPORT std::string _basename;
...@@ -93,7 +98,7 @@ IPAACA_HEADER_EXPORT class BufferConfiguration//{{{ ...@@ -93,7 +98,7 @@ IPAACA_HEADER_EXPORT class BufferConfiguration//{{{
};//}}} };//}}}
/// Builder object for BufferConfiguration, not required for C++ [DEPRECATED] /// Builder object for BufferConfiguration, not required for C++ [DEPRECATED]
IPAACA_HEADER_EXPORT class BufferConfigurationBuilder: private BufferConfiguration//{{{ class BufferConfigurationBuilder: private BufferConfiguration//{{{
{ {
public: public:
[[deprecated("Use setters in BufferConfiguration instead of the Builder")]] [[deprecated("Use setters in BufferConfiguration instead of the Builder")]]
...@@ -122,13 +127,13 @@ IPAACA_HEADER_EXPORT class BufferConfigurationBuilder: private BufferConfigurati ...@@ -122,13 +127,13 @@ IPAACA_HEADER_EXPORT class BufferConfigurationBuilder: private BufferConfigurati
* evt_type is one of IU_ADDED, IU_UPDATED, IU_RETRACTED, IU_DELETED, IU_LINKSUPDATED, IU_COMMITTED, IU_MESSAGE<br/> * evt_type is one of IU_ADDED, IU_UPDATED, IU_RETRACTED, IU_DELETED, IU_LINKSUPDATED, IU_COMMITTED, IU_MESSAGE<br/>
* local indicates that a remote change to a local IU (in an OutputBuffer) was effected * local indicates that a remote change to a local IU (in an OutputBuffer) was effected
* *
* * See #Buffer::register_handler for examples on how to use your own handlers.
*/ */
IPAACA_HEADER_EXPORT typedef boost::function<void (boost::shared_ptr<IUInterface>, IUEventType, bool)> IUEventHandlerFunction; IPAACA_HEADER_EXPORT typedef std::function<void (std::shared_ptr<IUInterface>, IUEventType, bool)> IUEventHandlerFunction;
/** \brief Internal handler type used in Buffer (wraps used-specified IUEventHandlerFunction) /** \brief Internal handler type used in Buffer (wraps used-specified IUEventHandlerFunction)
*/ */
IPAACA_HEADER_EXPORT class IUEventHandler {//{{{ class IUEventHandler {//{{{
protected: protected:
IPAACA_MEMBER_VAR_EXPORT IUEventHandlerFunction _function; IPAACA_MEMBER_VAR_EXPORT IUEventHandlerFunction _function;
IPAACA_MEMBER_VAR_EXPORT IUEventType _event_mask; IPAACA_MEMBER_VAR_EXPORT IUEventType _event_mask;
...@@ -142,9 +147,8 @@ IPAACA_HEADER_EXPORT class IUEventHandler {//{{{ ...@@ -142,9 +147,8 @@ IPAACA_HEADER_EXPORT class IUEventHandler {//{{{
public: 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::string& category);
IPAACA_HEADER_EXPORT IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories); 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, std::shared_ptr<IUInterface> iu, 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 std::shared_ptr<IUEventHandler> ptr;
typedef boost::shared_ptr<IUEventHandler> ptr;
};//}}} };//}}}
/** /**
...@@ -152,15 +156,16 @@ IPAACA_HEADER_EXPORT class IUEventHandler {//{{{ ...@@ -152,15 +156,16 @@ IPAACA_HEADER_EXPORT class IUEventHandler {//{{{
* *
* \b Note: This class is never instantiated directly (use OutputBuffer and InputBuffer, respectively). * \b Note: This class is never instantiated directly (use OutputBuffer and InputBuffer, respectively).
*/ */
IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Buffer> {//{{{ class Buffer {
friend class IU; friend class IU;
friend class RemotePushIU; friend class RemotePushIU;
friend class CallbackIUPayloadUpdate; /*friend class CallbackIUPayloadUpdate;
friend class CallbackIULinkUpdate; friend class CallbackIULinkUpdate;
friend class CallbackIUCommission; friend class CallbackIUCommission;
friend class CallbackIUResendRequest; friend class CallbackIUResendRequest;*/
friend class ipaaca::backend::LocalServer;
friend class ipaaca::backend::Listener;
protected: protected:
//Lock _handler_lock;
IPAACA_MEMBER_VAR_EXPORT std::string _uuid; IPAACA_MEMBER_VAR_EXPORT std::string _uuid;
IPAACA_MEMBER_VAR_EXPORT std::string _basename; IPAACA_MEMBER_VAR_EXPORT std::string _basename;
IPAACA_MEMBER_VAR_EXPORT std::string _unique_name; IPAACA_MEMBER_VAR_EXPORT std::string _unique_name;
...@@ -168,24 +173,21 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu ...@@ -168,24 +173,21 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu
IPAACA_MEMBER_VAR_EXPORT std::string _channel; IPAACA_MEMBER_VAR_EXPORT std::string _channel;
IPAACA_MEMBER_VAR_EXPORT std::vector<IUEventHandler::ptr> _event_handlers; IPAACA_MEMBER_VAR_EXPORT std::vector<IUEventHandler::ptr> _event_handlers;
protected: protected:
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _publish_iu_resend(boost::shared_ptr<IU> iu, const std::string& hidden_scope_name) = 0; IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _publish_iu_resend(std::shared_ptr<IU> iu, const std::string& hidden_scope_name) = 0;
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_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, PayloadDocumentEntry::ptr>& 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_payload_update(IUInterface* iu, bool is_delta, revision_t revision, const std::map<std::string, PayloadDocumentEntry::ptr>& 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 _IPAACA_ABSTRACT_ virtual void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name="undef") = 0;
// IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _send_iu_resendrequest(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 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) { IPAACA_HEADER_EXPORT inline Buffer(const std::string& basename, const std::string& function) {
_allocate_unique_name(basename, function); _allocate_unique_name(basename, function);
_channel = __ipaaca_static_option_default_channel; _channel = __ipaaca_static_option_default_channel;
} }
IPAACA_HEADER_EXPORT void call_iu_event_handlers(boost::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category); IPAACA_HEADER_EXPORT void call_iu_event_handlers(std::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category);
public: public:
IPAACA_HEADER_EXPORT virtual inline ~Buffer() { } IPAACA_HEADER_EXPORT virtual inline ~Buffer() { }
IPAACA_HEADER_EXPORT inline const std::string& unique_name() { return _unique_name; } IPAACA_HEADER_EXPORT inline const std::string& unique_name() { return _unique_name; }
/// This version of register_handler takes a set of several category interests instead of just one.
IPAACA_HEADER_EXPORT void register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories);
/** \brief Register a user-specified handler for IU events. Unless specified, it triggers for all event types for all category interests of the buffer. /** \brief Register a user-specified handler for IU events. Unless specified, it triggers for all event types for all category interests of the buffer.
* *
* \param function A function [object] that can be converted to #IUEventHandlerFunction (examples below) * \param function A function [object] that can be converted to #IUEventHandlerFunction (examples below)
...@@ -205,7 +207,7 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu ...@@ -205,7 +207,7 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu
* } * }
* </pre> * </pre>
* *
* Adding a class member as a handler (using boost::bind):<br/> * Adding a class member as a handler (using macro or std::bind):<br/>
* <pre> * <pre>
* class MyClass { * class MyClass {
* protected: * protected:
...@@ -214,7 +216,11 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu ...@@ -214,7 +216,11 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu
* public: * public:
* MyClass() { * MyClass() {
* inbuf = InputBuffer::create("bufname", "categoryInterest"); * inbuf = InputBuffer::create("bufname", "categoryInterest");
* inbuf->register_handler(boost::bind(&MyClass::my_internal_iu_handler, this, _1, _2, _3)); * // Using the macro may protect you against future code adaptations:
* inbuf->register_handler(IPAACA_BIND_CLASS_HANDLER(&MyClass::my_internal_iu_handler, this));
* // it is currently identical to:
* // inbuf->register_handler(std::bind(&MyClass::my_internal_iu_handler, this, \
* std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
* } * }
* }; * };
* </pre> * </pre>
...@@ -228,9 +234,10 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu ...@@ -228,9 +234,10 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu
* *
*/ */
IPAACA_HEADER_EXPORT void register_handler(IUEventHandlerFunction function, IUEventType event_mask = IU_ALL_EVENTS, const std::string& category=""); 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; /// This version of register_handler takes a set of several category interests instead of just one.
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual boost::shared_ptr<IUInterface> get(const std::string& iu_uid) = 0; IPAACA_HEADER_EXPORT void register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories);
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual std::set<boost::shared_ptr<IUInterface> > get_ius() = 0; IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual std::shared_ptr<IUInterface> get(const std::string& iu_uid) = 0;
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual std::set<std::shared_ptr<IUInterface> > get_ius() = 0;
IPAACA_HEADER_EXPORT inline const std::string& channel() { return _channel; } IPAACA_HEADER_EXPORT inline const std::string& channel() { return _channel; }
}; };
...@@ -239,59 +246,52 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu ...@@ -239,59 +246,52 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu
/** /**
* \brief A buffer to which own IUs can be added to publish them * \brief A buffer to which own IUs can be added to publish them
* *
* Use OutputBuffer::create() to obtain a smart pointer to a new output buffer. * Use #OutputBuffer::create to obtain a smart pointer to a new output buffer.
* *
* Use OutputBuffer::add() to add (= publish) an IU. * Use #OutputBuffer::add to add (= publish) an IU.
* *
* Use OutputBuffer::remove() to remove (= retract) an IU. * Use #OutputBuffer::remove to remove (= retract) an IU.
* *
* Use Buffer::register_handler() to register a handler that will respond to remote changes to own published IUs. * Use #Buffer::register_handler to register a handler that will respond to remote changes to own published IUs.
*/ */
IPAACA_HEADER_EXPORT class OutputBuffer: public Buffer { //, public boost::enable_shared_from_this<OutputBuffer> {//{{{ class OutputBuffer: public Buffer {
friend class IU; friend class IU;
friend class RemotePushIU; friend class RemotePushIU;
friend class OutputBufferRsbAdaptor; friend class ipaaca::backend::LocalServer;
protected: protected:
protected: protected:
//OutputBufferRsbAdaptor _rsb;
IPAACA_MEMBER_VAR_EXPORT IUStore _iu_store; IPAACA_MEMBER_VAR_EXPORT IUStore _iu_store;
IPAACA_MEMBER_VAR_EXPORT Lock _iu_id_counter_lock; IPAACA_MEMBER_VAR_EXPORT Lock _iu_id_counter_lock;
#ifdef IPAACA_EXPOSE_FULL_RSB_API #ifdef IPAACA_EXPOSE_FULL_RSB_API
protected: protected:
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, rsb::Informer<rsb::AnyType>::Ptr> _informer_store; IPAACA_MEMBER_VAR_EXPORT std::map<std::string, ipaaca::backend::Informer::ptr> _informer_store;
IPAACA_MEMBER_VAR_EXPORT rsb::patterns::ServerPtr _server; IPAACA_MEMBER_VAR_EXPORT ipaaca::backend::LocalServer::ptr _server;
IPAACA_HEADER_EXPORT rsb::Informer<rsb::AnyType>::Ptr _get_informer(const std::string& category); IPAACA_HEADER_EXPORT ipaaca::backend::Informer::ptr _get_informer(const std::string& category);
#endif #endif
protected: 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_OVERRIDE_; 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_OVERRIDE_;
IPAACA_HEADER_EXPORT void _publish_iu_resend(boost::shared_ptr<IU> iu, const std::string& hidden_scope_name) _IPAACA_OVERRIDE_; IPAACA_HEADER_EXPORT void _publish_iu_resend(std::shared_ptr<IU> iu, const std::string& hidden_scope_name) _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void _send_iu_payload_update(IUInterface* iu, bool is_delta, revision_t revision, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="undef") _IPAACA_OVERRIDE_; IPAACA_HEADER_EXPORT void _send_iu_payload_update(IUInterface* iu, bool is_delta, revision_t revision, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="undef") _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name) _IPAACA_OVERRIDE_; IPAACA_HEADER_EXPORT void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name) _IPAACA_OVERRIDE_;
//IPAACA_HEADER_EXPORT void _send_iu_resendrequest(IUInterface* iu, revision_t revision, const std::string& writer_name); IPAACA_HEADER_EXPORT void _publish_iu(std::shared_ptr<IU> iu);
// remote access functions /// mark and send IU retraction on own IU (removal from buffer is in remove(IU))
// _remote_update_links(IULinkUpdate) IPAACA_HEADER_EXPORT void _retract_iu(std::shared_ptr<IU> iu);
// _remote_update_payload(IUPayloadUpdate) /// mark and send retraction for all unretracted IUs (without removal, used in ~OutputBuffer)
// _remote_commit(protobuf::IUCommission) IPAACA_HEADER_EXPORT void _retract_all_internal();
IPAACA_HEADER_EXPORT void _publish_iu(boost::shared_ptr<IU> iu);
IPAACA_HEADER_EXPORT void _retract_iu(boost::shared_ptr<IU> iu);
protected: protected:
/// \b Note: constructor is protected. Use create() /// \b Note: constructor is protected. Use create()
IPAACA_HEADER_EXPORT OutputBuffer(const std::string& basename, const std::string& channel=""); // empty string auto-replaced with __ipaaca_static_option_default_channel IPAACA_HEADER_EXPORT OutputBuffer(const std::string& basename, const std::string& channel=""); // empty string auto-replaced with __ipaaca_static_option_default_channel
IPAACA_HEADER_EXPORT void _initialize_server(); IPAACA_HEADER_EXPORT void _initialize_server();
public: public:
IPAACA_HEADER_EXPORT static boost::shared_ptr<OutputBuffer> create(const std::string& basename); IPAACA_HEADER_EXPORT static std::shared_ptr<OutputBuffer> create(const std::string& basename);
IPAACA_HEADER_EXPORT ~OutputBuffer() { /// OutputBuffer destructor will retract all IUs that are still live
IPAACA_IMPLEMENT_ME IPAACA_HEADER_EXPORT ~OutputBuffer();
} IPAACA_HEADER_EXPORT void add(std::shared_ptr<IU> iu);
IPAACA_HEADER_EXPORT void add(boost::shared_ptr<IU> iu); IPAACA_HEADER_EXPORT std::shared_ptr<IU> remove(const std::string& iu_uid);
IPAACA_HEADER_EXPORT boost::shared_ptr<IU> remove(const std::string& iu_uid); IPAACA_HEADER_EXPORT std::shared_ptr<IU> remove(std::shared_ptr<IU> iu);
IPAACA_HEADER_EXPORT boost::shared_ptr<IU> remove(boost::shared_ptr<IU> iu); IPAACA_HEADER_EXPORT std::shared_ptr<IUInterface> get(const std::string& iu_uid) _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT boost::shared_ptr<IUInterface> get(const std::string& iu_uid) _IPAACA_OVERRIDE_; IPAACA_HEADER_EXPORT std::set<std::shared_ptr<IUInterface> > get_ius() _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT std::set<boost::shared_ptr<IUInterface> > get_ius() _IPAACA_OVERRIDE_; typedef std::shared_ptr<OutputBuffer> ptr;
typedef boost::shared_ptr<OutputBuffer> ptr;
}; };
//}}} //}}}
...@@ -304,27 +304,26 @@ IPAACA_HEADER_EXPORT class OutputBuffer: public Buffer { //, public boost::enabl ...@@ -304,27 +304,26 @@ IPAACA_HEADER_EXPORT class OutputBuffer: public Buffer { //, public boost::enabl
* *
* Use Buffer::register_handler() to register a handler that will respond to relevant remote IUs. * Use Buffer::register_handler() to register a handler that will respond to relevant remote IUs.
*/ */
IPAACA_HEADER_EXPORT class InputBuffer: public Buffer { //, public boost::enable_shared_from_this<InputBuffer> {//{{{ class InputBuffer: public Buffer {
friend class IU; friend class IU;
friend class RemotePushIU; friend class RemotePushIU;
friend class InputBufferRsbAdaptor; friend class ipaaca::backend::Listener;
//InputBufferRsbAdaptor _rsb;
#ifdef IPAACA_EXPOSE_FULL_RSB_API #ifdef IPAACA_EXPOSE_FULL_RSB_API
protected: protected:
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, rsb::ListenerPtr> _listener_store; IPAACA_MEMBER_VAR_EXPORT std::map<std::string, ipaaca::backend::Listener::ptr> _listener_store;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, rsb::patterns::RemoteServerPtr> _remote_server_store; IPAACA_MEMBER_VAR_EXPORT std::map<std::string, ipaaca::backend::RemoteServer::ptr> _remote_server_store;
IPAACA_MEMBER_VAR_EXPORT RemotePushIUStore _iu_store; // TODO genericize IPAACA_MEMBER_VAR_EXPORT RemotePushIUStore _iu_store;
IPAACA_HEADER_EXPORT rsb::patterns::RemoteServerPtr _get_remote_server(const std::string& unique_server_name); IPAACA_HEADER_EXPORT ipaaca::backend::RemoteServer::ptr _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 ipaaca::backend::Listener::ptr _create_category_listener_if_needed(const std::string& category);
IPAACA_HEADER_EXPORT void _handle_iu_events(rsb::EventPtr event); IPAACA_HEADER_EXPORT void _handle_iu_events(ipaaca::backend::Event::ptr event);
IPAACA_HEADER_EXPORT void _trigger_resend_request(rsb::EventPtr event); IPAACA_HEADER_EXPORT void _trigger_resend_request(ipaaca::backend::Event::ptr event);
#endif #endif
protected: 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_OVERRIDE_ 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_OVERRIDE_
{ {
IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_link_update() should never be invoked") IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_link_update() should never be invoked")
} }
IPAACA_HEADER_EXPORT inline void _publish_iu_resend(boost::shared_ptr<IU> iu, const std::string& hidden_scope_name) _IPAACA_OVERRIDE_ IPAACA_HEADER_EXPORT inline void _publish_iu_resend(std::shared_ptr<IU> iu, const std::string& hidden_scope_name) _IPAACA_OVERRIDE_
{ {
IPAACA_WARNING("(ERROR) InputBuffer::_publish_iu_resend() should never be invoked") IPAACA_WARNING("(ERROR) InputBuffer::_publish_iu_resend() should never be invoked")
} }
...@@ -357,35 +356,33 @@ IPAACA_HEADER_EXPORT class InputBuffer: public Buffer { //, public boost::enable ...@@ -357,35 +356,33 @@ IPAACA_HEADER_EXPORT class InputBuffer: public Buffer { //, public boost::enable
IPAACA_HEADER_EXPORT void set_resend(bool resendActive); IPAACA_HEADER_EXPORT void set_resend(bool resendActive);
IPAACA_HEADER_EXPORT bool get_resend(); IPAACA_HEADER_EXPORT bool get_resend();
/// Create InputBuffer according to configuration in BufferConfiguration object /// Create InputBuffer according to configuration in BufferConfiguration object
IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const BufferConfiguration& bufferconfiguration); IPAACA_HEADER_EXPORT static std::shared_ptr<InputBuffer> create(const BufferConfiguration& bufferconfiguration);
/// Create InputBuffer from name and set of category interests /// Create InputBuffer from name and set of category interests
IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::set<std::string>& category_interests); IPAACA_HEADER_EXPORT static std::shared_ptr<InputBuffer> create(const std::string& basename, const std::set<std::string>& category_interests);
/// Create InputBuffer from name and vector of category interests /// Create InputBuffer from name and vector of category interests
IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::vector<std::string>& category_interests); IPAACA_HEADER_EXPORT static std::shared_ptr<InputBuffer> create(const std::string& basename, const std::vector<std::string>& category_interests);
// /// Create InputBuffer from name and initializer_list of category interests
// IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::initializer_list<std::string>& category_interests);
/// Convenience function: create InputBuffer from name and one category interest /// Convenience function: create InputBuffer from name and one category interest
IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1); IPAACA_HEADER_EXPORT static std::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1);
/// Convenience function: create InputBuffer from name and two category interests [DEPRECATED] /// Convenience function: create InputBuffer from name and two category interests [DEPRECATED]
[[deprecated("Use create(string, set<string>) instead")]] [[deprecated("Use create(string, set<string>) instead")]]
IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2); IPAACA_HEADER_EXPORT static std::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2);
/// Convenience function: create InputBuffer from name and three category interests [DEPRECATED] /// Convenience function: create InputBuffer from name and three category interests [DEPRECATED]
[[deprecated("Use create(string, set<string>) instead")]] [[deprecated("Use create(string, set<string>) instead")]]
IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3); IPAACA_HEADER_EXPORT static std::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3);
/// Convenience function: create InputBuffer from name and four category interests [DEPRECATED] /// Convenience function: create InputBuffer from name and four category interests [DEPRECATED]
[[deprecated("Use create(string, set<string>) instead")]] [[deprecated("Use create(string, set<string>) instead")]]
IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3, const std::string& category_interest4); IPAACA_HEADER_EXPORT static std::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_HEADER_EXPORT ~InputBuffer() {
IPAACA_IMPLEMENT_ME IPAACA_IMPLEMENT_ME
} }
IPAACA_HEADER_EXPORT boost::shared_ptr<IUInterface> get(const std::string& iu_uid) _IPAACA_OVERRIDE_; IPAACA_HEADER_EXPORT std::shared_ptr<IUInterface> get(const std::string& iu_uid) _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT std::set<boost::shared_ptr<IUInterface> > get_ius() _IPAACA_OVERRIDE_; IPAACA_HEADER_EXPORT std::set<std::shared_ptr<IUInterface> > get_ius() _IPAACA_OVERRIDE_;
typedef boost::shared_ptr<InputBuffer> ptr; typedef std::shared_ptr<InputBuffer> ptr;
}; };
//}}} //}}}
/// Internal, transport-independent, representation of payload updates /// Internal, transport-independent, representation of payload updates
IPAACA_HEADER_EXPORT class IUPayloadUpdate {//{{{ class IUPayloadUpdate {//{{{
public: public:
IPAACA_MEMBER_VAR_EXPORT std::string uid; IPAACA_MEMBER_VAR_EXPORT std::string uid;
IPAACA_MEMBER_VAR_EXPORT revision_t revision; IPAACA_MEMBER_VAR_EXPORT revision_t revision;
...@@ -394,12 +391,14 @@ IPAACA_HEADER_EXPORT class IUPayloadUpdate {//{{{ ...@@ -394,12 +391,14 @@ IPAACA_HEADER_EXPORT class IUPayloadUpdate {//{{{
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, PayloadDocumentEntry::ptr> new_items; IPAACA_MEMBER_VAR_EXPORT std::map<std::string, PayloadDocumentEntry::ptr> new_items;
IPAACA_MEMBER_VAR_EXPORT std::vector<std::string> keys_to_remove; IPAACA_MEMBER_VAR_EXPORT std::vector<std::string> keys_to_remove;
IPAACA_MEMBER_VAR_EXPORT std::string payload_type; // to handle legacy mode IPAACA_MEMBER_VAR_EXPORT std::string payload_type; // to handle legacy mode
IPAACA_MEMBER_VAR_EXPORT std::string request_uid; // for lightweight back-ends
IPAACA_MEMBER_VAR_EXPORT std::string request_endpoint; // for lightweight back-ends
friend std::ostream& operator<<(std::ostream& os, const IUPayloadUpdate& obj); friend std::ostream& operator<<(std::ostream& os, const IUPayloadUpdate& obj);
typedef boost::shared_ptr<IUPayloadUpdate> ptr; typedef std::shared_ptr<IUPayloadUpdate> ptr;
};//}}} };//}}}
/// Internal, transport-independent, representation of link updates /// Internal, transport-independent, representation of link updates
IPAACA_HEADER_EXPORT class IULinkUpdate {//{{{ class IULinkUpdate {//{{{
public: public:
IPAACA_MEMBER_VAR_EXPORT std::string uid; IPAACA_MEMBER_VAR_EXPORT std::string uid;
IPAACA_MEMBER_VAR_EXPORT revision_t revision; IPAACA_MEMBER_VAR_EXPORT revision_t revision;
...@@ -407,8 +406,10 @@ IPAACA_HEADER_EXPORT class IULinkUpdate {//{{{ ...@@ -407,8 +406,10 @@ IPAACA_HEADER_EXPORT class IULinkUpdate {//{{{
IPAACA_MEMBER_VAR_EXPORT bool is_delta; 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> > new_links;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, std::set<std::string> > links_to_remove; IPAACA_MEMBER_VAR_EXPORT std::map<std::string, std::set<std::string> > links_to_remove;
IPAACA_MEMBER_VAR_EXPORT std::string request_uid; // for lightweight back-ends
IPAACA_MEMBER_VAR_EXPORT std::string request_endpoint; // for lightweight back-ends
friend std::ostream& operator<<(std::ostream& os, const IULinkUpdate& obj); friend std::ostream& operator<<(std::ostream& os, const IULinkUpdate& obj);
typedef boost::shared_ptr<IULinkUpdate> ptr; typedef std::shared_ptr<IULinkUpdate> ptr;
};//}}} };//}}}
......
/*
* 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-cmdline_parser.h
*
* \brief Header file for basic command line parser
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date February, 2019
*/
#ifndef __ipaaca_cmdline_parser_h_INCLUDED__
#define __ipaaca_cmdline_parser_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
// in ipaaca-cmdline-parser.cc
// additional misc classes ( Command line options )//{{{
/** \brief Command line argument container for CommandLineParser
*
* Contains the results of argument parsing from CommandLineParser::parse()
*
* The parser is preconfigured to handle some standard options:
*
* Option | Function
* --------------------------------|------------------------------------------------------------------------------
* --help | Print list of available options
* --verbose | Set verbose flag
* --character-name <name> | Set character name (legacy)
* --component-name <name> | Set component name (legacy)
* --ipaaca-payload-type <type> | Set default ipaaca payload type (default JSON, set STR for legacy protocol)
* --ipaaca-default-channel <name> | Set default channel name (default 'default')
* --ipaaca-enable-logging <level> | Set console log level, one of NONE, DEBUG, INFO, WARNING, ERROR, CRITICAL
* --rsb-enable-logging <level> | Set rsb (transport) log level
*
*/
class CommandLineOptions {
public:
IPAACA_HEADER_EXPORT inline CommandLineOptions()
{ }
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);
/// Get the option argument or default value (if the option expected an argument)
IPAACA_HEADER_EXPORT std::string get_param(const std::string& o);
/// Check whether option has been set
IPAACA_HEADER_EXPORT bool is_set(const std::string& o);
IPAACA_HEADER_EXPORT void dump();
public:
typedef std::shared_ptr<CommandLineOptions> ptr;
};
/**
* \brief Command line parser for ipaaca programs.
*
* The parser is preconfigured to handle some standard options:
*
* Option | Function
* --------------------------------|------------------------------------------------------------------------------
* --help | Print list of available options
* --verbose | Set verbose flag
* --character-name <name> | Set character name (legacy)
* --component-name <name> | Set component name (legacy)
* --ipaaca-payload-type <type> | Set default ipaaca payload type (default JSON, set STR for legacy protocol)
* --ipaaca-default-channel <name> | Set default channel name (default 'default')
* --ipaaca-enable-logging <level> | Set console log level, one of NONE, DEBUG, INFO, WARNING, ERROR, CRITICAL
* --rsb-enable-logging <level> | Set rsb (transport) log level
*
*/
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();
IPAACA_MEMBER_VAR_EXPORT bool library_options_handled;
IPAACA_HEADER_EXPORT bool consume_library_option(const std::string& name, bool expect, const char* optarg);
IPAACA_HEADER_EXPORT void ensure_defaults_in( CommandLineOptions::ptr clo );
public:
IPAACA_HEADER_EXPORT inline ~CommandLineParser() { }
/// Create a new parser object reference.
IPAACA_HEADER_EXPORT static inline std::shared_ptr<CommandLineParser> create() {
return std::shared_ptr<CommandLineParser>(new CommandLineParser());
}
IPAACA_HEADER_EXPORT void initialize_parser_defaults();
IPAACA_HEADER_EXPORT void dump_options();
/** \brief Add a user-defined option
*
* \param optname The long option name, e.g. verbose for --verbose
* \param shortn The short option (or \0 for none)
* \param expect_param Whether an argument is expected for the option
* \param defaultv The default string value (unused if expect_param is false)
*/
IPAACA_HEADER_EXPORT void add_option(const std::string& optname, char shortn, bool expect_param, const std::string& defaultv);
/** \brief Parse argument list and return result.
*
* Parse argument list (e.g. from main()) with the parser, consuming the internal options.
* The remaining options are packaged into a CommandLineOptions object.
*/
IPAACA_HEADER_EXPORT CommandLineOptions::ptr parse(int argc, char* const* argv);
public:
typedef std::shared_ptr<CommandLineParser> ptr;
};
//}}}
#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-backend.h
*
* \brief Header file for abstract backend participant implementation
* (used in the core library and as a base to derive specific backends).
*
* Users should not include this file directly, but use ipaaca.h
*
* \b Note: This file is only included during compilation of ipaaca,
* for regular use, the full internal API is not exposed.
* Users generally need never touch the internal transport layer.
*
* \author Ramin Yaghoubzadeh Torky (ryaghoubzadeh@uni-bielefeld.de)
* \date December, 2018
*/
#ifndef __ipaaca_config_h_INCLUDED__
#define __ipaaca_config_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
class Config {
public:
typedef std::shared_ptr<Config> ptr;
protected:
std::map<std::string, std::string> _data;
std::set<std::string> _messages_delivered;
template<typename T> T get_with_default_internal(const std::string& key, T const& default_value, bool warn);
template<typename T> void config_key_not_found(const std::string& key, T const& default_value, bool warn)
{
if (!_messages_delivered.count(key)) {
if (warn) { IPAACA_WARNING("Config: no key '" << key << "', using default value " << default_value) }
else { IPAACA_DEBUG("Config: no key '" << key << "', using default value " << default_value) }
_messages_delivered.insert(key);
}
}
template<typename T> void config_conversion_failed(const std::string& key, T const& default_value)
{
if (!_messages_delivered.count(key)) {
IPAACA_WARNING("Config: failed conversion for key '" << key << "', using default value " << default_value)
_messages_delivered.insert(key);
}
}
bool get_key_and_value(const std::string& line, std::string& key, std::string& value);
public:
inline std::map<std::string, std::string>::const_iterator data_cbegin() const { return _data.begin(); }
inline std::map<std::string, std::string>::const_iterator data_cend() const { return _data.end(); }
void populate_from_global_sources();
void populate_from_environment();
void populate_from_any_conf_files();
void populate_from_conf_file(std::fstream& fs);
template<typename T> T get_with_default(const std::string& key, T const& default_value) {
return get_with_default_internal(key, default_value, false);
}
template<typename T> T get_with_default_and_warning(const std::string& key, T const& default_value) {
return get_with_default_internal(key, default_value, true);
}
//inline std::map<std::string, std::string>::iterator begin() { return std::map<std::string, std::string>::begin(); }
//inline std::map<std::string, std::string>::iterator end() { return std::map<std::string, std::string>::end(); }
};
Config::ptr get_global_config(bool auto_parse_on_demand=true);
#endif
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -49,88 +49,58 @@ ...@@ -49,88 +49,58 @@
* \date March, 2015 * \date March, 2015
*/ */
#ifndef __ipaaca_internal_h_INCLUDED__ #ifndef __ipaaca_converters_h_INCLUDED__
#define __ipaaca_internal_h_INCLUDED__ #define __ipaaca_converters_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__ #ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead" #error "Please do not include this file directly, use ipaaca.h instead"
#endif #endif
namespace converters {
#ifdef IPAACA_EXPOSE_FULL_RSB_API // Wrap a serialized inner object and a wire type in a protobuf::TransportLevelWrapper
std::string cooked_message(const std::string& raw_message, ipaaca::protobuf::TransportMessageType msg_type);
// ??? ///IPAACA_HEADER_EXPORT inline std::string json_to_string(PayloadDocumentEntry::ptr entry); // protobuf serialization for all supported types (replaces converter repository)
std::string internal_serialize(std::shared_ptr<ipaaca::IU> iu);
//std::string internal_serialize(std::shared_ptr<ipaaca::Message> msg);
std::string internal_serialize(std::shared_ptr<ipaaca::IUPayloadUpdate> pup);
std::string internal_serialize(std::shared_ptr<ipaaca::IULinkUpdate> lup);
std::string internal_serialize(std::shared_ptr<protobuf::RemoteRequestResult> pb);
std::string internal_serialize(std::shared_ptr<protobuf::IURetraction> pb);
std::string internal_serialize(std::shared_ptr<protobuf::IUCommission> pb);
std::string internal_serialize(std::shared_ptr<protobuf::IUResendRequest> pb);
std::string internal_serialize(std::shared_ptr<protobuf::IUPayloadUpdateRequest> pb);
std::string internal_serialize(std::shared_ptr<protobuf::IULinkUpdateRequest> pb);
std::string internal_serialize(std::shared_ptr<protobuf::IUCommissionRequest> pb);
IPAACA_HEADER_EXPORT class CallbackIUPayloadUpdate: public rsb::patterns::Server::Callback<IUPayloadUpdate, int> {//{{{ // deserialization (just switching here instead of the converter registry business)
protected: std::shared_ptr<ipaaca::backend::Event> internal_deserialize(const std::string& wire);
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 CallbackIUResendRequest: public rsb::patterns::Server::Callback<protobuf::IUResendRequest, int> {//{{{
protected:
IPAACA_MEMBER_VAR_EXPORT Buffer* _buffer;
public:
IPAACA_HEADER_EXPORT CallbackIUResendRequest(Buffer* buffer);
public:
IPAACA_HEADER_EXPORT boost::shared_ptr<int> call(const std::string& methodName, boost::shared_ptr<protobuf::IUResendRequest> 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> {//{{{ class IUConverter {//{{{
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: public:
IPAACA_HEADER_EXPORT MessageConverter(); IPAACA_HEADER_EXPORT static std::string serialize(std::shared_ptr<ipaaca::IU> iu); // const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT std::string serialize(const rsb::AnnotatedData& data, std::string& wire); IPAACA_HEADER_EXPORT static std::shared_ptr<ipaaca::IUInterface> deserialize(const 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> {//{{{ /*
IPAACA_HEADER_EXPORT class MessageConverter {//{{{
public: public:
IPAACA_HEADER_EXPORT IUPayloadUpdateConverter(); IPAACA_HEADER_EXPORT static std::string serialize(std::shared_ptr<ipaaca::Message> msg); // const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT std::string serialize(const rsb::AnnotatedData& data, std::string& wire); IPAACA_HEADER_EXPORT static std::shared_ptr<ipaaca::RemoteMessage> deserialize(const 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> {//{{{ */
class IUPayloadUpdateConverter {//{{{
public: public:
IPAACA_HEADER_EXPORT IULinkUpdateConverter(); IPAACA_HEADER_EXPORT static std::string serialize(std::shared_ptr<ipaaca::IUPayloadUpdate> pup); // const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT std::string serialize(const rsb::AnnotatedData& data, std::string& wire); IPAACA_HEADER_EXPORT static std::shared_ptr<ipaaca::IUPayloadUpdate> deserialize(const 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> {//{{{ class IULinkUpdateConverter {//{{{
public: public:
IPAACA_HEADER_EXPORT IntConverter(); IPAACA_HEADER_EXPORT static std::string serialize(std::shared_ptr<ipaaca::IULinkUpdate> lup); // const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT std::string serialize(const rsb::AnnotatedData& data, std::string& wire); IPAACA_HEADER_EXPORT static std::shared_ptr<ipaaca::IULinkUpdate> deserialize(const std::string& wire);
IPAACA_HEADER_EXPORT rsb::AnnotatedData deserialize(const std::string& wireSchema, const std::string& wire);
};//}}} };//}}}
#endif
#endif } // of namespace converters
#endif // __ipaaca_converters_h_INCLUDED__
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -49,9 +49,6 @@ ...@@ -49,9 +49,6 @@
#error "Please do not include this file directly, use ipaaca.h instead" #error "Please do not include this file directly, use ipaaca.h instead"
#endif #endif
// LAST FIXME LAST
//typedef boost::shared_ptr<rapidjson::Document> JsonDocPtr;
typedef uint32_t revision_t; 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 /// 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
...@@ -90,7 +87,7 @@ IPAACA_HEADER_EXPORT inline std::string iu_event_type_to_str(IUEventType type) ...@@ -90,7 +87,7 @@ IPAACA_HEADER_EXPORT inline std::string iu_event_type_to_str(IUEventType 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 /// 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
IPAACA_HEADER_EXPORT enum IUAccessMode { enum IUAccessMode {
IU_ACCESS_PUSH, IU_ACCESS_PUSH,
IU_ACCESS_REMOTE, IU_ACCESS_REMOTE,
IU_ACCESS_MESSAGE IU_ACCESS_MESSAGE
...@@ -99,315 +96,4 @@ IPAACA_HEADER_EXPORT enum IUAccessMode { ...@@ -99,315 +96,4 @@ IPAACA_HEADER_EXPORT enum IUAccessMode {
/// generate a UUID as an ASCII string /// generate a UUID as an ASCII string
IPAACA_HEADER_EXPORT std::string generate_uuid_string(); IPAACA_HEADER_EXPORT std::string generate_uuid_string();
/**
* Exception with string description
*/
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();
}
};//}}}
/// IU was not found in a buffer
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";
}
};//}}}
/// IU was already published
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";
}
};//}}}
/// IU had already been committed to
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";
}
};//}}}
/// Remote IU update failed because it had been modified in the mean time
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";
}
};//}}}
/// Requested resend of old IU due to malformed channel specification
IPAACA_HEADER_EXPORT class IUResendRequestFailedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUResendRequestFailedError() throw() { }
IPAACA_HEADER_EXPORT inline IUResendRequestFailedError() { //boost::shared_ptr<IU> iu) {
_description = "IUResendRequestFailedError";
}
};//}}}
/// Write operation failed because IU had been set read-only
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";
}
};//}}}
/// Buffer::add() failed because the IU had been previously placed in another buffer
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";
}
};//}}}
/// A request was made that is only valid for an already published IU
IPAACA_HEADER_EXPORT class IUUnpublishedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUUnpublishedError() throw() { }
IPAACA_HEADER_EXPORT inline IUUnpublishedError() { //boost::shared_ptr<IU> iu) {
_description = "IUUnpublishedError";
}
};//}}}
/// IU had already been allocated a UID
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";
}
};//}}}
/// IU had already been allocated an owner name
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";
}
};//}}}
/// UID generation failed (Windows only)
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";
}
};//}}}
/// Not implemented (e.g. invalid request parameters via backend)
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";
}
};//}}}
/// PayloadEntryProxy requested type conversion failed (including lenient interpretation)
IPAACA_HEADER_EXPORT class PayloadTypeConversionError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadTypeConversionError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadTypeConversionError() { //boost::shared_ptr<IU> iu) {
_description = "PayloadTypeConversionError";
}
};//}}}
/// PayloadEntryProxy was addressed as list when not a list or as map when not a map
IPAACA_HEADER_EXPORT class PayloadAddressingError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadAddressingError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadAddressingError() { //boost::shared_ptr<IU> iu) {
_description = "PayloadAddressingError";
}
};//}}}
/// Malformed json was received for a Payload
IPAACA_HEADER_EXPORT class JsonParsingError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~JsonParsingError() throw() { }
IPAACA_HEADER_EXPORT inline JsonParsingError() { //boost::shared_ptr<IU> iu) {
_description = "JsonParsingError";
}
};//}}}
/// PayloadEntryProxy invalidated (unused)
IPAACA_HEADER_EXPORT class PayloadEntryProxyInvalidatedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadEntryProxyInvalidatedError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadEntryProxyInvalidatedError() { //boost::shared_ptr<IU> iu) {
_description = "PayloadEntryProxyInvalidatedError";
}
};//}}}
/// Iterator over Payload entries was invalidated by an intermediate IU update operation
IPAACA_HEADER_EXPORT class PayloadIteratorInvalidError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadIteratorInvalidError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadIteratorInvalidError() { //boost::shared_ptr<IU> iu) {
_description = "PayloadIteratorInvalidError";
}
};//}}}
/** \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).
*/
IPAACA_HEADER_EXPORT 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. 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:
IPAACA_HEADER_EXPORT static void auto_configure_rsb();
IPAACA_MEMBER_VAR_EXPORT static bool _initialized;
};
// in ipaaca-cmdline-parser.cc
// additional misc classes ( Command line options )//{{{
/** \brief Command line argument container for CommandLineParser
*
* Contains the results of argument parsing from CommandLineParser::parse()
*
* The parser is preconfigured to handle some standard options:
*
* Option | Function
* --------------------------------|------------------------------------------------------------------------------
* --help | Print list of available options
* --verbose | Set verbose flag
* --character-name <name> | Set character name (legacy)
* --component-name <name> | Set component name (legacy)
* --ipaaca-payload-type <type> | Set default ipaaca payload type (default JSON, set STR for legacy protocol)
* --ipaaca-default-channel <name> | Set default channel name (default 'default')
* --ipaaca-enable-logging <level> | Set console log level, one of NONE, DEBUG, INFO, WARNING, ERROR, CRITICAL
* --rsb-enable-logging <level> | Set rsb (transport) log level
*
*/
IPAACA_HEADER_EXPORT class CommandLineOptions {
public:
IPAACA_HEADER_EXPORT inline CommandLineOptions()
//: _unconsumed_argc(0), _unconsumed_argv(nullptr)
{ }
IPAACA_HEADER_EXPORT inline ~CommandLineOptions() {
//if (_unconsumed_argv) delete[] _unconsumed_argv;
}
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);
/// Get the option argument or default value (if the option expected an argument)
IPAACA_HEADER_EXPORT std::string get_param(const std::string& o);
/// Check whether option has been set
IPAACA_HEADER_EXPORT bool is_set(const std::string& o);
IPAACA_HEADER_EXPORT void dump();
public:
//IPAACA_HEADER_EXPORT inline int unconsumed_argc() { return _unconsumed_argc; }
//IPAACA_HEADER_EXPORT inline char** unconsumed_argv() { return _unconsumed_argv; }
protected:
//IPAACA_MEMBER_VAR_EXPORT int _unconsumed_argc;
//IPAACA_MEMBER_VAR_EXPORT char** _unconsumed_argv;
public:
typedef boost::shared_ptr<CommandLineOptions> ptr;
};
/**
* \brief Command line parser for ipaaca programs.
*
* The parser is preconfigured to handle some standard options:
*
* Option | Function
* --------------------------------|------------------------------------------------------------------------------
* --help | Print list of available options
* --verbose | Set verbose flag
* --character-name <name> | Set character name (legacy)
* --component-name <name> | Set component name (legacy)
* --ipaaca-payload-type <type> | Set default ipaaca payload type (default JSON, set STR for legacy protocol)
* --ipaaca-default-channel <name> | Set default channel name (default 'default')
* --ipaaca-enable-logging <level> | Set console log level, one of NONE, DEBUG, INFO, WARNING, ERROR, CRITICAL
* --rsb-enable-logging <level> | Set rsb (transport) log level
*
*/
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();
IPAACA_MEMBER_VAR_EXPORT bool library_options_handled;
IPAACA_HEADER_EXPORT bool consume_library_option(const std::string& name, bool expect, const char* optarg);
IPAACA_HEADER_EXPORT void ensure_defaults_in( CommandLineOptions::ptr clo );
public:
IPAACA_HEADER_EXPORT inline ~CommandLineParser() { }
/// Create a new parser object reference.
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();
/** \brief Add a user-defined option
*
* \param optname The long option name, e.g. verbose for --verbose
* \param shortn The short option (or \0 for none)
* \param expect_param Whether an argument is expected for the option
* \param defaultv The default string value (unused if expect_param is false)
*/
IPAACA_HEADER_EXPORT void add_option(const std::string& optname, char shortn, bool expect_param, const std::string& defaultv);
/** \brief Parse argument list and return result.
*
* Parse argument list (e.g. from main()) with the parser, consuming the internal options.
* The remaining options are packaged into a CommandLineOptions object.
*/
IPAACA_HEADER_EXPORT CommandLineOptions::ptr parse(int argc, char* const* argv);
typedef boost::shared_ptr<CommandLineParser> ptr;
};
//}}}
// 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 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 );
//}}}
#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-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
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -52,9 +52,18 @@ ...@@ -52,9 +52,18 @@
/* /*
* forward declarations * forward declarations
*/ */
namespace backend {
//class Scope;
class Event;
class Informer;
class Listener;
class LocalServer;
class RemoteServer;
} // of namespace backend
class PayloadDocumentEntry; class PayloadDocumentEntry;
//class PayloadDocumentStore;
class PayloadBatchUpdateLock;
class PayloadEntryProxy; class PayloadEntryProxy;
class Payload; class Payload;
class PayloadIterator; class PayloadIterator;
...@@ -62,6 +71,7 @@ class IUInterface; ...@@ -62,6 +71,7 @@ class IUInterface;
class IU; class IU;
class Message; class Message;
class RemotePushIU; class RemotePushIU;
class RemoteMessage;
class IULinkUpdate; class IULinkUpdate;
class IUPayloadUpdate; class IUPayloadUpdate;
class IUStore; class IUStore;
...@@ -80,7 +90,7 @@ class IUConverter; ...@@ -80,7 +90,7 @@ class IUConverter;
class MessageConverter; class MessageConverter;
class IUPayloadUpdateConverter; class IUPayloadUpdateConverter;
class IULinkUpdateConverter; class IULinkUpdateConverter;
class IntConverter; //class IntConverter;
class BufferConfiguration; class BufferConfiguration;
class BufferConfigurationBuilder; class BufferConfigurationBuilder;
......
/*
* 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
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -58,9 +58,9 @@ ...@@ -58,9 +58,9 @@
* contains most generic user-space functions. * contains most generic user-space functions.
* *
*/ */
IPAACA_HEADER_EXPORT class IUInterface {//{{{ class IUInterface {//{{{
friend class IUConverter; friend class ipaaca::converters::IUConverter;
friend class MessageConverter; //friend class ipaaca::converters::MessageConverter;
friend std::ostream& operator<<(std::ostream& os, const IUInterface& obj); friend std::ostream& operator<<(std::ostream& os, const IUInterface& obj);
protected: protected:
IPAACA_HEADER_EXPORT IUInterface(); IPAACA_HEADER_EXPORT IUInterface();
...@@ -76,7 +76,7 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{ ...@@ -76,7 +76,7 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{
IPAACA_MEMBER_VAR_EXPORT bool _retracted; IPAACA_MEMBER_VAR_EXPORT bool _retracted;
IPAACA_MEMBER_VAR_EXPORT IUAccessMode _access_mode; IPAACA_MEMBER_VAR_EXPORT IUAccessMode _access_mode;
IPAACA_MEMBER_VAR_EXPORT bool _read_only; IPAACA_MEMBER_VAR_EXPORT bool _read_only;
//boost::shared_ptr<Buffer> _buffer; //std::shared_ptr<Buffer> _buffer;
IPAACA_MEMBER_VAR_EXPORT Buffer* _buffer; IPAACA_MEMBER_VAR_EXPORT Buffer* _buffer;
IPAACA_MEMBER_VAR_EXPORT SmartLinkMap _links; IPAACA_MEMBER_VAR_EXPORT SmartLinkMap _links;
protected: protected:
...@@ -85,7 +85,7 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{ ...@@ -85,7 +85,7 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{
// e.g. sending a notification across the network // 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_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; 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(boost::shared_ptr<Buffer> buffer); //void _set_buffer(std::shared_ptr<Buffer> buffer);
IPAACA_HEADER_EXPORT void _associate_with_buffer(Buffer* buffer); IPAACA_HEADER_EXPORT void _associate_with_buffer(Buffer* buffer);
IPAACA_HEADER_EXPORT void _set_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_uid(const std::string& uid);
...@@ -95,6 +95,8 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{ ...@@ -95,6 +95,8 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{
IPAACA_HEADER_EXPORT void _add_and_remove_links(const LinkMap& add, const LinkMap& remove) { _links._add_and_remove_links(add, remove); } IPAACA_HEADER_EXPORT void _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); } IPAACA_HEADER_EXPORT void _replace_links(const LinkMap& links) { _links._replace_links(links); }
public: 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). /// Return whether IU has already been published (is in a Buffer).
IPAACA_HEADER_EXPORT inline bool is_published() { return (_buffer != 0); } IPAACA_HEADER_EXPORT inline bool is_published() { return (_buffer != 0); }
/// Return auto-generated UID string (set during IU construction) /// Return auto-generated UID string (set during IU construction)
...@@ -115,7 +117,7 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{ ...@@ -115,7 +117,7 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{
IPAACA_HEADER_EXPORT inline IUAccessMode access_mode() const { return _access_mode; } 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) /// 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; } IPAACA_HEADER_EXPORT inline bool read_only() const { return _read_only; }
//inline boost::shared_ptr<Buffer> buffer() { return _buffer; } //inline std::shared_ptr<Buffer> buffer() { return _buffer; }
/// Return owning buffer [CAVEAT: do not rely on this function for future code] /// Return owning buffer [CAVEAT: do not rely on this function for future code]
IPAACA_HEADER_EXPORT inline Buffer* buffer() const { return _buffer; } 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 /// Return the link set for an arbitrary link type (e.g. "grounded_in"), or EMPTY_LINK_SET
...@@ -131,7 +133,7 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{ ...@@ -131,7 +133,7 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{
/// Commit to an IU (only possible for the IU owner) /// Commit to an IU (only possible for the IU owner)
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void commit() = 0; IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void commit() = 0;
// functions to modify and update links: // functions to modify and update links:
//IPAACA_HEADER_EXPORT void _publish_resend(boost::shared_ptr<IU> iu, const std::string& hidden_scope_name); //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 /// 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 = ""); IPAACA_HEADER_EXPORT void add_links(const std::string& type, const LinkSet& targets, const std::string& writer_name = "");
...@@ -146,7 +148,7 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{ ...@@ -146,7 +148,7 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{
IPAACA_HEADER_EXPORT void add_link(const std::string& type, const std::string& target, const std::string& writer_name = ""); 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) /// 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 = ""); 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; typedef std::shared_ptr<IUInterface> ptr;
};//}}} };//}}}
/** \brief Class of locally-owned IU objects. /** \brief Class of locally-owned IU objects.
...@@ -157,14 +159,11 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{ ...@@ -157,14 +159,11 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{
* *
* See IUInterface for a generic description of most user-space member functions. * See IUInterface for a generic description of most user-space member functions.
*/ */
IPAACA_HEADER_EXPORT class IU: public IUInterface {//{{{ class IU: public IUInterface {//{{{
friend class Buffer; friend class Buffer;
friend class InputBuffer; friend class InputBuffer;
friend class OutputBuffer; friend class OutputBuffer;
friend class CallbackIUPayloadUpdate; friend class ipaaca::backend::LocalServer;
friend class CallbackIULinkUpdate;
friend class CallbackIUCommission;
friend class CallbackIUResendRequest;
public: public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload; IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected: protected:
...@@ -174,24 +173,20 @@ IPAACA_HEADER_EXPORT class IU: public IUInterface {//{{{ ...@@ -174,24 +173,20 @@ IPAACA_HEADER_EXPORT class IU: public IUInterface {//{{{
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 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: public:
IPAACA_HEADER_EXPORT inline ~IU() { IPAACA_HEADER_EXPORT inline ~IU() {
//IPAACA_IMPLEMENT_ME
} }
[[deprecated("Please use the new argument order: category, payload_type, read_only")]] [[deprecated("Please use the new argument order: category, payload_type, read_only")]]
IPAACA_HEADER_EXPORT static boost::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, IUAccessMode access_mode, bool read_only=false, const std::string& payload_type="" );
IPAACA_HEADER_EXPORT static boost::shared_ptr<IU> create(const std::string& category, const std::string& payload_type="", bool read_only=false); 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 Payload& payload() _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; } IPAACA_HEADER_EXPORT inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT void commit() _IPAACA_OVERRIDE_; IPAACA_HEADER_EXPORT void commit() _IPAACA_OVERRIDE_;
protected: 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_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 _publish_resend(boost::shared_ptr<IU> iu, const std::string& hidden_scope_name);
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_; 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: protected:
IPAACA_HEADER_EXPORT virtual void _internal_commit(const std::string& writer_name = ""); IPAACA_HEADER_EXPORT virtual void _internal_commit(const std::string& writer_name = "");
public: public:
typedef boost::shared_ptr<IU> ptr; typedef std::shared_ptr<IU> ptr;
};//}}} };//}}}
/** \brief Class of locally-owned message objects ('one-shot' IUs). /** \brief Class of locally-owned message objects ('one-shot' IUs).
* *
...@@ -205,47 +200,42 @@ IPAACA_HEADER_EXPORT class IU: public IUInterface {//{{{ ...@@ -205,47 +200,42 @@ IPAACA_HEADER_EXPORT class IU: public IUInterface {//{{{
* *
* \see IU, IUInterface * \see IU, IUInterface
*/ */
IPAACA_HEADER_EXPORT class Message: public IU {//{{{ class Message: public IU {//{{{
friend class Buffer; friend class Buffer;
friend class InputBuffer; friend class InputBuffer;
friend class OutputBuffer; friend class OutputBuffer;
friend class CallbackIUPayloadUpdate; friend class ipaaca::backend::LocalServer;
friend class CallbackIULinkUpdate;
friend class CallbackIUCommission;
friend class CallbackIUResendRequest;
protected: protected:
IPAACA_HEADER_EXPORT Message(const std::string& category, IUAccessMode access_mode=IU_ACCESS_MESSAGE, bool read_only=true, const std::string& payload_type="" ); IPAACA_HEADER_EXPORT Message(const std::string& category, IUAccessMode access_mode=IU_ACCESS_MESSAGE, bool read_only=true, const std::string& payload_type="" );
public: public:
IPAACA_HEADER_EXPORT inline ~Message() { IPAACA_HEADER_EXPORT inline ~Message() {
//IPAACA_IMPLEMENT_ME
} }
[[deprecated("Please use the new argument order: category, payload_type")]] [[deprecated("Please use the new argument order: category, payload_type")]]
IPAACA_HEADER_EXPORT static boost::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, IUAccessMode access_mode, bool read_only=true, const std::string& payload_type="" );
IPAACA_HEADER_EXPORT static boost::shared_ptr<Message> create(const std::string& category, const std::string& payload_type=""); IPAACA_HEADER_EXPORT static std::shared_ptr<Message> create(const std::string& category, const std::string& payload_type="");
protected: 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_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_; 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: protected:
IPAACA_HEADER_EXPORT void _internal_commit(const std::string& writer_name = ""); IPAACA_HEADER_EXPORT void _internal_commit(const std::string& writer_name = "");
public: public:
typedef boost::shared_ptr<Message> ptr; 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. /// Copy of a remote IU, received in an InputBuffer. Setter functions call RPC over the backend (RSB). \b Note: Typically handled only as reference in a handler in user space.
IPAACA_HEADER_EXPORT class RemotePushIU: public IUInterface {//{{{ class RemotePushIU: public IUInterface {//{{{
friend class Buffer; friend class Buffer;
friend class InputBuffer; friend class InputBuffer;
friend class OutputBuffer; friend class OutputBuffer;
friend class IUConverter; friend class ipaaca::converters::IUConverter;
friend class MessageConverter; //friend class ipaaca::converters::MessageConverter;
public: public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload; IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected: protected:
IPAACA_HEADER_EXPORT RemotePushIU(); IPAACA_HEADER_EXPORT RemotePushIU();
IPAACA_HEADER_EXPORT static boost::shared_ptr<RemotePushIU> create(); IPAACA_HEADER_EXPORT static std::shared_ptr<RemotePushIU> create();
public: public:
IPAACA_HEADER_EXPORT inline ~RemotePushIU() { IPAACA_HEADER_EXPORT inline ~RemotePushIU() {
//IPAACA_IMPLEMENT_ME
} }
IPAACA_HEADER_EXPORT inline Payload& payload() _IPAACA_OVERRIDE_ { return _payload; } 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 inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; }
...@@ -258,23 +248,22 @@ IPAACA_HEADER_EXPORT class RemotePushIU: public IUInterface {//{{{ ...@@ -258,23 +248,22 @@ IPAACA_HEADER_EXPORT class RemotePushIU: public IUInterface {//{{{
IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update); IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_commission(); IPAACA_HEADER_EXPORT void _apply_commission();
IPAACA_HEADER_EXPORT void _apply_retraction(); IPAACA_HEADER_EXPORT void _apply_retraction();
typedef boost::shared_ptr<RemotePushIU> ptr; 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. /// Copy of a remote Message, received in an InputBuffer. Setter functions all fail.\b Note: Typically handled only as reference in a handler in user space.
IPAACA_HEADER_EXPORT class RemoteMessage: public IUInterface {//{{{ class RemoteMessage: public IUInterface {//{{{
friend class Buffer; friend class Buffer;
friend class InputBuffer; friend class InputBuffer;
friend class OutputBuffer; friend class OutputBuffer;
friend class IUConverter; friend class ipaaca::converters::IUConverter;
friend class MessageConverter; //friend class ipaaca::converters::MessageConverter;
public: public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload; IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected: protected:
IPAACA_HEADER_EXPORT RemoteMessage(); IPAACA_HEADER_EXPORT RemoteMessage();
IPAACA_HEADER_EXPORT static boost::shared_ptr<RemoteMessage> create(); IPAACA_HEADER_EXPORT static std::shared_ptr<RemoteMessage> create();
public: public:
IPAACA_HEADER_EXPORT inline ~RemoteMessage() { IPAACA_HEADER_EXPORT inline ~RemoteMessage() {
//IPAACA_IMPLEMENT_ME
} }
IPAACA_HEADER_EXPORT inline Payload& payload() _IPAACA_OVERRIDE_ { return _payload; } 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 inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; }
...@@ -287,21 +276,22 @@ IPAACA_HEADER_EXPORT class RemoteMessage: public IUInterface {//{{{ ...@@ -287,21 +276,22 @@ IPAACA_HEADER_EXPORT class RemoteMessage: public IUInterface {//{{{
IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update); IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_commission(); IPAACA_HEADER_EXPORT void _apply_commission();
IPAACA_HEADER_EXPORT void _apply_retraction(); IPAACA_HEADER_EXPORT void _apply_retraction();
typedef boost::shared_ptr<RemoteMessage> ptr; typedef std::shared_ptr<RemoteMessage> ptr;
};//}}} };//}}}
#ifdef IPAACA_BUILD_MOCK_OBJECTS
/// Mock IU for testing purposes. [INTERNAL] /// Mock IU for testing purposes. [INTERNAL]
IPAACA_HEADER_EXPORT class FakeIU: public IUInterface {//{{{ class FakeIU: public IUInterface {//{{{
friend class Buffer; friend class Buffer;
friend class InputBuffer; friend class InputBuffer;
friend class OutputBuffer; friend class OutputBuffer;
friend class IUConverter; friend class ipaaca::converters::IUConverter;
friend class MessageConverter; //friend class ipaaca::converters::MessageConverter;
protected: protected:
IPAACA_MEMBER_VAR_EXPORT Payload _payload; IPAACA_MEMBER_VAR_EXPORT Payload _payload;
IPAACA_HEADER_EXPORT FakeIU(); IPAACA_HEADER_EXPORT FakeIU();
public: public:
IPAACA_HEADER_EXPORT static boost::shared_ptr<FakeIU> create(); IPAACA_HEADER_EXPORT static std::shared_ptr<FakeIU> create();
IPAACA_HEADER_EXPORT ~FakeIU(); IPAACA_HEADER_EXPORT ~FakeIU();
IPAACA_HEADER_EXPORT Payload& payload() _IPAACA_OVERRIDE_; IPAACA_HEADER_EXPORT Payload& payload() _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT const Payload& const_payload() const _IPAACA_OVERRIDE_; IPAACA_HEADER_EXPORT const Payload& const_payload() const _IPAACA_OVERRIDE_;
...@@ -316,7 +306,8 @@ IPAACA_HEADER_EXPORT class FakeIU: public IUInterface {//{{{ ...@@ -316,7 +306,8 @@ IPAACA_HEADER_EXPORT class FakeIU: public IUInterface {//{{{
IPAACA_HEADER_EXPORT void _apply_commission(); IPAACA_HEADER_EXPORT void _apply_commission();
IPAACA_HEADER_EXPORT void _apply_retraction(); IPAACA_HEADER_EXPORT void _apply_retraction();
public: public:
typedef boost::shared_ptr<FakeIU> ptr; typedef std::shared_ptr<FakeIU> ptr;
};//}}} };//}}}
#endif
#endif #endif
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -51,13 +51,10 @@ ...@@ -51,13 +51,10 @@
/// Reentrant lock/mutex class /// Reentrant lock/mutex class
#ifdef WIN32 class Lock
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/thread.hpp>
IPAACA_HEADER_EXPORT class Lock
{ {
protected: protected:
IPAACA_MEMBER_VAR_EXPORT boost::recursive_mutex _mutex; std::recursive_mutex _mutex;
public: public:
IPAACA_HEADER_EXPORT inline Lock() { IPAACA_HEADER_EXPORT inline Lock() {
} }
...@@ -65,36 +62,17 @@ IPAACA_HEADER_EXPORT class Lock ...@@ -65,36 +62,17 @@ IPAACA_HEADER_EXPORT class Lock
} }
IPAACA_HEADER_EXPORT inline void lock() { IPAACA_HEADER_EXPORT inline void lock() {
_mutex.lock(); _mutex.lock();
on_lock();
} }
IPAACA_HEADER_EXPORT inline void unlock() { IPAACA_HEADER_EXPORT inline void unlock() {
on_unlock();
_mutex.unlock(); _mutex.unlock();
} }
}; IPAACA_HEADER_EXPORT virtual inline void on_lock() {
#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() { IPAACA_HEADER_EXPORT virtual inline void on_unlock() {
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);
} }
}; };
#endif
/** \brief Stack-based lock holder. /** \brief Stack-based lock holder.
* *
...@@ -102,7 +80,7 @@ IPAACA_HEADER_EXPORT class Lock ...@@ -102,7 +80,7 @@ IPAACA_HEADER_EXPORT class Lock
* (i.e. {}-block) and it will obtain the lock and * (i.e. {}-block) and it will obtain the lock and
* auto-release in on exiting the stack frame. * auto-release in on exiting the stack frame.
*/ */
IPAACA_HEADER_EXPORT class Locker class Locker
{ {
protected: protected:
IPAACA_MEMBER_VAR_EXPORT Lock* _lock; IPAACA_MEMBER_VAR_EXPORT Lock* _lock;
...@@ -123,8 +101,11 @@ IPAACA_HEADER_EXPORT class Locker ...@@ -123,8 +101,11 @@ IPAACA_HEADER_EXPORT class Locker
* *
* \see Locker * \see Locker
*/ */
#ifndef WIN32 #if _WIN32 || _WIN64
IPAACA_HEADER_EXPORT class PthreadMutexLocker // nothing for Windows
#else
#include <pthread.h>
class PthreadMutexLocker
{ {
protected: protected:
IPAACA_MEMBER_VAR_EXPORT pthread_mutex_t* _lock; IPAACA_MEMBER_VAR_EXPORT pthread_mutex_t* _lock;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -53,16 +53,16 @@ ...@@ -53,16 +53,16 @@
// casting operators from Value& // 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. /// 'Smart' type conversions, allowing for some leeway type-wise (e.g. string "1.3" can be successfully cast to double or long). Used by PayloadEntryProxy.
IPAACA_HEADER_EXPORT template<typename T> T json_value_cast(const rapidjson::Value&); template<typename T> T json_value_cast(const rapidjson::Value&);
IPAACA_HEADER_EXPORT template<typename T> T json_value_cast(const rapidjson::Value* value) { if (!value) return T(); return json_value_cast<T>(*value); } template<typename T> T json_value_cast(const rapidjson::Value* value) { if (!value) return T(); return json_value_cast<T>(*value); }
IPAACA_HEADER_EXPORT template<> long json_value_cast(const rapidjson::Value&); template<> IPAACA_HEADER_EXPORT long json_value_cast(const rapidjson::Value&);
IPAACA_HEADER_EXPORT template<> int json_value_cast(const rapidjson::Value&); template<> IPAACA_HEADER_EXPORT int json_value_cast(const rapidjson::Value&);
IPAACA_HEADER_EXPORT template<> double json_value_cast(const rapidjson::Value&); template<> IPAACA_HEADER_EXPORT double json_value_cast(const rapidjson::Value&);
IPAACA_HEADER_EXPORT template<> bool json_value_cast(const rapidjson::Value&); template<> IPAACA_HEADER_EXPORT bool json_value_cast(const rapidjson::Value&);
IPAACA_HEADER_EXPORT template<> std::string json_value_cast(const rapidjson::Value&); template<> IPAACA_HEADER_EXPORT std::string json_value_cast(const rapidjson::Value&);
IPAACA_HEADER_EXPORT template<> std::vector<std::string> json_value_cast(const rapidjson::Value&); template<> IPAACA_HEADER_EXPORT std::vector<std::string> json_value_cast(const rapidjson::Value&);
IPAACA_HEADER_EXPORT template<> std::list<std::string> json_value_cast(const rapidjson::Value&); template<> IPAACA_HEADER_EXPORT std::list<std::string> json_value_cast(const rapidjson::Value&);
IPAACA_HEADER_EXPORT template<> std::map<std::string, 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 // 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); //IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, T t);
...@@ -80,7 +80,7 @@ IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Doc ...@@ -80,7 +80,7 @@ IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Doc
IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const char*); 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 // 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. /// Setter to store a vector of supported basic types into json value, used by PayloadEntryProxy.
IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::vector<T>& ts) template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::vector<T>& ts)
{ {
valueobject.SetArray(); valueobject.SetArray();
for (auto& val: ts) { for (auto& val: ts) {
...@@ -90,7 +90,7 @@ IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::V ...@@ -90,7 +90,7 @@ IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::V
} }
} }
/// Setter to store a list of supported basic types into json value, used by PayloadEntryProxy. /// Setter to store a list of supported basic types into json value, used by PayloadEntryProxy.
IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::list<T>& ts) template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::list<T>& ts)
{ {
valueobject.SetArray(); valueobject.SetArray();
for (auto& val: ts) { for (auto& val: ts) {
...@@ -100,7 +100,7 @@ IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::V ...@@ -100,7 +100,7 @@ IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::V
} }
} }
/// Setter to store a map of string -> supported basic types into json value, used by PayloadEntryProxy. /// Setter to store a map of string -> supported basic types into json value, used by PayloadEntryProxy.
IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::map<std::string, T>& ts) template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::map<std::string, T>& ts)
{ {
valueobject.SetObject(); valueobject.SetObject();
for (auto& val: ts) { for (auto& val: ts) {
...@@ -111,43 +111,35 @@ IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::V ...@@ -111,43 +111,35 @@ IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::V
valueobject.AddMember(key, newv, allocator); valueobject.AddMember(key, newv, allocator);
} }
} }
/*IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::vector<std::string>&);
IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::list<std::string>&);
IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::map<std::string, std::string>&);
*/
// FIXME TODO locking / invalidating proxy on first write of a payload entry
/// Single payload entry wrapping a rapidjson::Document with some conversion glue. Also handles copy-on-write Document cloning. <b>Internal type</b> - users generally do not see this. /// 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.
IPAACA_HEADER_EXPORT class PayloadDocumentEntry//{{{ class PayloadDocumentEntry//{{{
{ {
friend std::ostream& operator<<(std::ostream& os, std::shared_ptr<PayloadDocumentEntry> entry); friend std::ostream& operator<<(std::ostream& os, std::shared_ptr<PayloadDocumentEntry> entry);
public: public:
IPAACA_MEMBER_VAR_EXPORT ipaaca::Lock lock; IPAACA_MEMBER_VAR_EXPORT ipaaca::Lock lock;
IPAACA_MEMBER_VAR_EXPORT bool modified; IPAACA_MEMBER_VAR_EXPORT bool modified;
//IPAACA_MEMBER_VAR_EXPORT std::string json_source;
IPAACA_MEMBER_VAR_EXPORT rapidjson::Document document; IPAACA_MEMBER_VAR_EXPORT rapidjson::Document document;
IPAACA_HEADER_EXPORT inline PayloadDocumentEntry(): modified(false) { } IPAACA_HEADER_EXPORT inline PayloadDocumentEntry(): modified(false) { }
IPAACA_HEADER_EXPORT inline ~PayloadDocumentEntry() { } IPAACA_HEADER_EXPORT inline ~PayloadDocumentEntry() { }
//IPAACA_HEADER_EXPORT PayloadDocumentEntry(const std::string& source): modified(false), json_source(source), {};
IPAACA_HEADER_EXPORT std::string to_json_string_representation(); 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_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> from_unquoted_string_value(const std::string& input);
IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> create_null(); IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> create_null();
IPAACA_HEADER_EXPORT std::shared_ptr<PayloadDocumentEntry> clone(); IPAACA_HEADER_EXPORT std::shared_ptr<PayloadDocumentEntry> clone();
IPAACA_HEADER_EXPORT rapidjson::Value& get_or_create_nested_value_from_proxy_path(PayloadEntryProxy* pep); IPAACA_HEADER_EXPORT rapidjson::Value& get_or_create_nested_value_from_proxy_path(PayloadEntryProxy* pep);
//IPAACA_HEADER_EXPORT void update_json_source();
typedef std::shared_ptr<PayloadDocumentEntry> ptr; typedef std::shared_ptr<PayloadDocumentEntry> ptr;
}; };
//}}} //}}}
typedef std::map<std::string, PayloadDocumentEntry::ptr> PayloadDocumentStore; 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) /** \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. * Obtained by calling payload() on any IUInterface derived object. Created during IU creation.
*/ */
IPAACA_HEADER_EXPORT class Payload//{{{ class Payload: public Lock //{{{
{ {
friend std::ostream& operator<<(std::ostream& os, const Payload& obj); friend std::ostream& operator<<(std::ostream& os, const Payload& obj);
friend class IUInterface; friend class IUInterface;
...@@ -155,30 +147,41 @@ IPAACA_HEADER_EXPORT class Payload//{{{ ...@@ -155,30 +147,41 @@ IPAACA_HEADER_EXPORT class Payload//{{{
friend class Message; friend class Message;
friend class RemotePushIU; friend class RemotePushIU;
friend class RemoteMessage; friend class RemoteMessage;
friend class IUConverter; friend class ipaaca::converters::IUConverter;
friend class MessageConverter; //friend class ipaaca::converters::MessageConverter;
friend class CallbackIUPayloadUpdate; friend class ipaaca::backend::LocalServer;
friend class PayloadEntryProxy; friend class PayloadEntryProxy;
friend class PayloadIterator; friend class PayloadIterator;
friend class FakeIU; friend class FakeIU;
protected: protected:
IPAACA_MEMBER_VAR_EXPORT std::string _owner_name; IPAACA_MEMBER_VAR_EXPORT std::string _owner_name;
//IPAACA_MEMBER_VAR_EXPORT rapidjson::Document _json_document;
//IPAACA_MEMBER_VAR_EXPORT std::map<std::string, rapidjson::Document> _json_store;
IPAACA_MEMBER_VAR_EXPORT PayloadDocumentStore _document_store; IPAACA_MEMBER_VAR_EXPORT PayloadDocumentStore _document_store;
IPAACA_MEMBER_VAR_EXPORT boost::weak_ptr<IUInterface> _iu; 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: protected:
IPAACA_HEADER_EXPORT void initialize(boost::shared_ptr<IUInterface> iu); 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 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_wipe();
IPAACA_HEADER_EXPORT void _remotely_enforced_delitem(const std::string& k); 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 _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_replace_all(const std::map<std::string, PayloadDocumentEntry::ptr>& new_contents, const std::string& writer_name=""); 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_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_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_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: 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; } IPAACA_HEADER_EXPORT inline const std::string& owner_name() { return _owner_name; }
// access // access
/// Obtain a payload item by name as a PayloadEntryProxy (returning null-type proxy if undefined) /// Obtain a payload item by name as a PayloadEntryProxy (returning null-type proxy if undefined)
...@@ -187,11 +190,6 @@ IPAACA_HEADER_EXPORT class Payload//{{{ ...@@ -187,11 +190,6 @@ IPAACA_HEADER_EXPORT class Payload//{{{
IPAACA_HEADER_EXPORT operator std::map<std::string, std::string>(); IPAACA_HEADER_EXPORT operator std::map<std::string, std::string>();
/// remove a single payload entry /// remove a single payload entry
IPAACA_HEADER_EXPORT inline void remove(const std::string& k) { _internal_remove(k); } IPAACA_HEADER_EXPORT inline void remove(const std::string& k) { _internal_remove(k); }
// FIXME: json: these two must support a bunch of standard types, not [only] json (users touch them)
// to be more precise: types of map<string, T> with T several interesting things (string, list<string>, etc.)
//IPAACA_HEADER_EXPORT inline void set(const std::map<std::string, const rapidjson::Document&>& all_elems) { _internal_replace_all(all_elems); }
//IPAACA_HEADER_EXPORT inline void merge(const std::map<std::string, const rapidjson::Document&>& elems_to_merge) { _internal_merge(elems_to_merge); }
// legacy / convenience setter
/// Legacy / convenience function: set the whole payload map from a map string->string (all JSON types are also set as string, no interpretation) /// 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); IPAACA_HEADER_EXPORT void set(const std::map<std::string, std::string>& all_elems);
protected: protected:
...@@ -201,7 +199,7 @@ IPAACA_HEADER_EXPORT class Payload//{{{ ...@@ -201,7 +199,7 @@ IPAACA_HEADER_EXPORT class Payload//{{{
public: public:
[[deprecated("Use operator[] and operator std::string() instead")]] [[deprecated("Use operator[] and operator std::string() instead")]]
/// Read a single entry as string [DEPRECATED] (use string conversion in PayloadEntryProxy instead) /// Read a single entry as string [DEPRECATED] (use string conversion in PayloadEntryProxy instead)
IPAACA_HEADER_EXPORT std::string get(const std::string& k); // DEPRECATED IPAACA_HEADER_EXPORT std::string get(const std::string& k);
protected: protected:
IPAACA_MEMBER_VAR_EXPORT unsigned long internal_revision; IPAACA_MEMBER_VAR_EXPORT unsigned long internal_revision;
IPAACA_MEMBER_VAR_EXPORT inline void mark_revision_change() { internal_revision++; } IPAACA_MEMBER_VAR_EXPORT inline void mark_revision_change() { internal_revision++; }
...@@ -211,7 +209,7 @@ IPAACA_HEADER_EXPORT class Payload//{{{ ...@@ -211,7 +209,7 @@ IPAACA_HEADER_EXPORT class Payload//{{{
IPAACA_HEADER_EXPORT PayloadIterator begin(); IPAACA_HEADER_EXPORT PayloadIterator begin();
/// obtain a standard iterator past the last entry in the payload /// obtain a standard iterator past the last entry in the payload
IPAACA_HEADER_EXPORT PayloadIterator end(); IPAACA_HEADER_EXPORT PayloadIterator end();
typedef boost::shared_ptr<Payload> ptr; typedef std::shared_ptr<Payload> ptr;
};//}}} };//}}}
/** \brief Standard iterator for Payload (example below) /** \brief Standard iterator for Payload (example below)
...@@ -225,7 +223,7 @@ IPAACA_HEADER_EXPORT class Payload//{{{ ...@@ -225,7 +223,7 @@ IPAACA_HEADER_EXPORT class Payload//{{{
* </pre> * </pre>
* *
*/ */
IPAACA_HEADER_EXPORT class PayloadIterator//{{{ class PayloadIterator//{{{
{ {
friend class Payload; friend class Payload;
friend std::ostream& operator<<(std::ostream& os, const PayloadIterator& iter); friend std::ostream& operator<<(std::ostream& os, const PayloadIterator& iter);
...@@ -233,7 +231,6 @@ IPAACA_HEADER_EXPORT class PayloadIterator//{{{ ...@@ -233,7 +231,6 @@ IPAACA_HEADER_EXPORT class PayloadIterator//{{{
IPAACA_MEMBER_VAR_EXPORT Payload* _payload; IPAACA_MEMBER_VAR_EXPORT Payload* _payload;
IPAACA_MEMBER_VAR_EXPORT unsigned long reference_payload_revision; IPAACA_MEMBER_VAR_EXPORT unsigned long reference_payload_revision;
IPAACA_MEMBER_VAR_EXPORT PayloadDocumentStore::iterator raw_iterator; IPAACA_MEMBER_VAR_EXPORT PayloadDocumentStore::iterator raw_iterator;
//IPAACA_MEMBER_VAR_EXPORT bool is_end;
protected: protected:
IPAACA_HEADER_EXPORT PayloadIterator(Payload* payload, PayloadDocumentStore::iterator&& pl_iter ); //, bool is_end); IPAACA_HEADER_EXPORT PayloadIterator(Payload* payload, PayloadDocumentStore::iterator&& pl_iter ); //, bool is_end);
public: public:
...@@ -243,15 +240,14 @@ IPAACA_HEADER_EXPORT class PayloadIterator//{{{ ...@@ -243,15 +240,14 @@ IPAACA_HEADER_EXPORT class PayloadIterator//{{{
IPAACA_HEADER_EXPORT std::shared_ptr<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);
IPAACA_HEADER_EXPORT bool operator!=(const PayloadIterator& ref); IPAACA_HEADER_EXPORT bool operator!=(const PayloadIterator& ref);
// constructor to create a new top-most parent proxy (from a payload key)
}; };
//}}} //}}}
/// Iterator over a payload entry that is a json map-type object (returned type during dereferencing: pair<string, PayloadEntryProxy>) /// Iterator over a payload entry that is a json map-type object (returned type during dereferencing: pair<string, PayloadEntryProxy>)
IPAACA_HEADER_EXPORT class PayloadEntryProxyMapIterator//{{{ class PayloadEntryProxyMapIterator//{{{
{ {
public: public:
typedef rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>::MemberIterator RawIterator; typedef rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>::ConstMemberIterator RawIterator;
protected: protected:
IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy; IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy;
IPAACA_MEMBER_VAR_EXPORT RawIterator raw_iterator; IPAACA_MEMBER_VAR_EXPORT RawIterator raw_iterator;
...@@ -265,7 +261,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyMapIterator//{{{ ...@@ -265,7 +261,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyMapIterator//{{{
}; };
//}}} //}}}
/// Iterator over a payload entry that is a json list-type object (returned type during dereferencing: PayloadEntryProxy) /// Iterator over a payload entry that is a json list-type object (returned type during dereferencing: PayloadEntryProxy)
IPAACA_HEADER_EXPORT class PayloadEntryProxyListIterator//{{{ class PayloadEntryProxyListIterator//{{{
{ {
protected: protected:
IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy; IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy;
...@@ -281,7 +277,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyListIterator//{{{ ...@@ -281,7 +277,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyListIterator//{{{
}; };
//}}} //}}}
/// Interpretation of a variant json value as a map-type object /// Interpretation of a variant json value as a map-type object
IPAACA_HEADER_EXPORT class PayloadEntryProxyMapDecorator//{{{ class PayloadEntryProxyMapDecorator//{{{
{ {
public: public:
IPAACA_HEADER_EXPORT inline PayloadEntryProxyMapDecorator(PayloadEntryProxy* proxy_): proxy(proxy_) { } IPAACA_HEADER_EXPORT inline PayloadEntryProxyMapDecorator(PayloadEntryProxy* proxy_): proxy(proxy_) { }
...@@ -292,7 +288,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyMapDecorator//{{{ ...@@ -292,7 +288,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyMapDecorator//{{{
}; };
//}}} //}}}
/// Interpretation of a variant json value as a list-type object /// Interpretation of a variant json value as a list-type object
IPAACA_HEADER_EXPORT class PayloadEntryProxyListDecorator//{{{ class PayloadEntryProxyListDecorator//{{{
{ {
public: public:
IPAACA_HEADER_EXPORT inline PayloadEntryProxyListDecorator(PayloadEntryProxy* proxy_): proxy(proxy_) { } IPAACA_HEADER_EXPORT inline PayloadEntryProxyListDecorator(PayloadEntryProxy* proxy_): proxy(proxy_) { }
...@@ -303,7 +299,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyListDecorator//{{{ ...@@ -303,7 +299,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyListDecorator//{{{
}; };
//}}} //}}}
/** \brief Reference to an existent or nonexistent payload entry (or a value deeper in the json tree) /** \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[]. * 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. * The proxy handles automatic type conversions, requests remote changes of payloads, and enables navigation into and iteration over structured json objects.
...@@ -318,7 +314,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyListDecorator//{{{ ...@@ -318,7 +314,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyListDecorator//{{{
* *
* <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 val: iu->payload()["my_list"].as_list()) { ... }</code> // as_list is required to select list-type iteration (value type in iteration remains variant)
* *
* <code>for (auto k_v_map: iu->payload()["my_map"].as_map()) { ... }</code> // as_map is required to select map-type iteration (value type in iteration is a pair, second part remains variant) * <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): * \b Examples (writing):
* *
...@@ -332,7 +328,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyListDecorator//{{{ ...@@ -332,7 +328,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyListDecorator//{{{
* *
* <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 * <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
*/ */
IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ class PayloadEntryProxy//{{{
{ {
friend class Payload; friend class Payload;
friend class PayloadIterator; friend class PayloadIterator;
...@@ -348,13 +344,9 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -348,13 +344,9 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
/// 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. /// 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(); IPAACA_HEADER_EXPORT PayloadEntryProxyListDecorator as_list();
protected: protected:
//IPAACA_MEMBER_VAR_EXPORT rapidjson::Document* _json_parent_node;
//IPAACA_MEMBER_VAR_EXPORT rapidjson::Document* _json_node;
IPAACA_MEMBER_VAR_EXPORT Payload* _payload; IPAACA_MEMBER_VAR_EXPORT Payload* _payload;
IPAACA_MEMBER_VAR_EXPORT std::string _key; IPAACA_MEMBER_VAR_EXPORT std::string _key;
//
// new json stuff / hierarchical navigation // new json stuff / hierarchical navigation
//
IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* parent; ///< Parent proxy (up to document root -> then null) IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* parent; ///< Parent proxy (up to document root -> then null)
IPAACA_MEMBER_VAR_EXPORT PayloadDocumentEntry::ptr document_entry; // contains lock and json Doc IPAACA_MEMBER_VAR_EXPORT 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 existent; ///< Whether Value exists already (or else 'blindly' navigated)
...@@ -363,10 +355,12 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -363,10 +355,12 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
IPAACA_MEMBER_VAR_EXPORT std::string addressed_key; ///< Key that was used in map-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) /// 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) IPAACA_MEMBER_VAR_EXPORT rapidjson::Value* json_value; ///< json value that corresponds to the current navigation (or nullptr)
/* protected:
IPAACA_HEADER_EXPORT void connect_to_existing_parents();
*/
protected: 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) // constructor to create a new top-most parent proxy (from a payload key)
IPAACA_HEADER_EXPORT PayloadEntryProxy(Payload* payload, const std::string& key); IPAACA_HEADER_EXPORT PayloadEntryProxy(Payload* payload, const std::string& key);
// constructors for navigation through objects // constructors for navigation through objects
...@@ -401,12 +395,11 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -401,12 +395,11 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const char* key); IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const char* key);
// //
/// Set or overwrite some portion of a payload from the point navigated to /// Set or overwrite some portion of a payload from the point navigated to
IPAACA_HEADER_EXPORT template<typename T> PayloadEntryProxy& operator=(T t) template<typename T> PayloadEntryProxy& operator=(T t)
{ {
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required 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); rapidjson::Value& newval = new_entry->get_or_create_nested_value_from_proxy_path(this);
pack_into_json_value(newval, new_entry->document.GetAllocator(), t); pack_into_json_value(newval, new_entry->document.GetAllocator(), t);
//new_entry->update_json_source();
_payload->set(_key, new_entry); _payload->set(_key, new_entry);
return *this; return *this;
} }
...@@ -415,7 +408,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -415,7 +408,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
/// Value comparison with other proxy contents /// Value comparison with other proxy contents
IPAACA_HEADER_EXPORT inline bool operator!=(const PayloadEntryProxy& otherproxy) { return !operator==(otherproxy); } IPAACA_HEADER_EXPORT inline bool operator!=(const PayloadEntryProxy& otherproxy) { return !operator==(otherproxy); }
/// Value comparison with supported basic types /// Value comparison with supported basic types
IPAACA_HEADER_EXPORT template<typename T> bool operator==(T othervalue) template<typename T> bool operator==(T othervalue)
{ {
if (!json_value) return false; if (!json_value) return false;
try { try {
...@@ -426,7 +419,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -426,7 +419,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
} }
} }
/// Value comparison with supported basic types /// Value comparison with supported basic types
IPAACA_HEADER_EXPORT template<typename T> bool operator!=(T othervalue) { return !operator==(othervalue); } template<typename T> bool operator!=(T othervalue) { return !operator==(othervalue); }
/// Value comparison with char* (required to be explicitly added) /// Value comparison with char* (required to be explicitly added)
IPAACA_HEADER_EXPORT inline bool operator==(const char* othervalue) IPAACA_HEADER_EXPORT inline bool operator==(const char* othervalue)
{ {
...@@ -439,13 +432,10 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -439,13 +432,10 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
/// Copy value from below other json node, preserving types /// Copy value from below other json node, preserving types
IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const PayloadEntryProxy& otherproxy); IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const PayloadEntryProxy& otherproxy);
//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);
/// Conversion to std::string (explicit or implicit) /// Conversion to std::string (explicit or implicit)
IPAACA_HEADER_EXPORT operator std::string(); IPAACA_HEADER_EXPORT operator std::string();
/// Conversion to int (explicit or implicit)
IPAACA_HEADER_EXPORT operator int();
/// Conversion to long (explicit or implicit) /// Conversion to long (explicit or implicit)
IPAACA_HEADER_EXPORT operator long(); IPAACA_HEADER_EXPORT operator long();
/// Conversion to double (explicit or implicit) /// Conversion to double (explicit or implicit)
...@@ -453,7 +443,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -453,7 +443,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
/// Conversion to bool (explicit or implicit) /// Conversion to bool (explicit or implicit)
IPAACA_HEADER_EXPORT operator bool(); IPAACA_HEADER_EXPORT operator bool();
/// Conversion to uniform std::vector of supported basic type /// Conversion to uniform std::vector of supported basic type
IPAACA_HEADER_EXPORT template<typename Inner> operator std::vector<Inner>() { template<typename Inner> operator std::vector<Inner>() {
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError(); if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
std::vector<Inner> result; std::vector<Inner> result;
for (auto it = json_value->Begin(); it != json_value->End(); ++it) { for (auto it = json_value->Begin(); it != json_value->End(); ++it) {
...@@ -462,7 +452,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -462,7 +452,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
return result; return result;
} }
/// Conversion to uniform std::list of supported basic type /// Conversion to uniform std::list of supported basic type
IPAACA_HEADER_EXPORT template<typename Inner> operator std::list<Inner>() { template<typename Inner> operator std::list<Inner>() {
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError(); if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
std::list<Inner> result; std::list<Inner> result;
for (auto it = json_value->Begin(); it != json_value->End(); ++it) { for (auto it = json_value->Begin(); it != json_value->End(); ++it) {
...@@ -471,7 +461,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -471,7 +461,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
return result; return result;
} }
/// Conversion to uniform std::map of string -> supported basic type /// Conversion to uniform std::map of string -> supported basic type
IPAACA_HEADER_EXPORT template<typename Inner> operator std::map<std::string, Inner>() { template<typename Inner> operator std::map<std::string, Inner>() {
if ((!json_value) || (!json_value->IsObject())) throw PayloadAddressingError(); if ((!json_value) || (!json_value->IsObject())) throw PayloadAddressingError();
std::map<std::string, Inner> result; std::map<std::string, Inner> result;
for (auto it = json_value->MemberBegin(); it != json_value->MemberEnd(); ++it) { for (auto it = json_value->MemberBegin(); it != json_value->MemberEnd(); ++it) {
...@@ -479,31 +469,28 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -479,31 +469,28 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
} }
return result; return result;
} }
// FIXME why are these needed again? // TODO maybe remove these deprecated converters later
/// [DECPRECATED] use normal type conversion syntax instead /// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator std::string() instead (i.e. explicit or implicit cast)")]] [[deprecated("Use operator std::string() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT std::string to_str(); IPAACA_HEADER_EXPORT std::string to_str();
//long to_int() { return operator long(); ; //long to_int() { return operator long(); ;
/// [DECPRECATED] use normal type conversion syntax instead /// [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)")]] [[deprecated("Use operator long() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT long to_long(); IPAACA_HEADER_EXPORT long to_long();
/// [DECPRECATED] use normal type conversion syntax instead /// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator double() instead (i.e. explicit or implicit cast)")]] [[deprecated("Use operator double() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT double to_float(); IPAACA_HEADER_EXPORT double to_float();
/// [DECPRECATED] use normal type conversion syntax instead /// [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)")]] [[deprecated("Use operator bool() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT bool to_bool(); IPAACA_HEADER_EXPORT bool to_bool();
// getters (not needed since conversions are enough?)
//IPAACA_HEADER_EXPORT template<typename T> T get() { return json_value_cast<T>(json_value); }
// setters
//IPAACA_HEADER_EXPORT template<typename T> PayloadEntryProxy& set(T t);
/*{
pack_into_json_value<T>(t);
connect_to_existing_parents();
_payload->set(key, document_entry->document);
}*/
/// Append a supported type to a list-type payload value /// Append a supported type to a list-type payload value
IPAACA_HEADER_EXPORT template<typename T> void push_back(T t) template<typename T> void push_back(T t)
{ {
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError(); if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
...@@ -528,7 +515,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -528,7 +515,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
_payload->set(_key, new_entry); _payload->set(_key, new_entry);
} }
/// Extend a list-type payload value with a vector containing items of a supported type /// Extend a list-type payload value with a vector containing items of a supported type
IPAACA_HEADER_EXPORT template<typename T> void extend(const std::vector<T>& ts) template<typename T> void extend(const std::vector<T>& ts)
{ {
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError(); if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
...@@ -541,7 +528,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -541,7 +528,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
_payload->set(_key, new_entry); _payload->set(_key, new_entry);
} }
/// Extend a list-type payload value with a list containing items of a supported type /// Extend a list-type payload value with a list containing items of a supported type
IPAACA_HEADER_EXPORT template<typename T> void extend(const std::list<T>& ts) template<typename T> void extend(const std::list<T>& ts)
{ {
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError(); if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
...@@ -569,18 +556,6 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ ...@@ -569,18 +556,6 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
_payload->set(_key, new_entry); _payload->set(_key, new_entry);
} }
}; };
// Available interpretations of payload entries (or children thereof) below.
// Usage of standard complex data structures (vector etc.) currently entails
// casting all entries to a uniform type (a-priori choice: std::string).
/*
IPAACA_HEADER_EXPORT template<> long PayloadEntryProxy::get();
IPAACA_HEADER_EXPORT template<> double PayloadEntryProxy::get();
IPAACA_HEADER_EXPORT template<> bool PayloadEntryProxy::get();
IPAACA_HEADER_EXPORT template<> std::string PayloadEntryProxy::get();
IPAACA_HEADER_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get();
IPAACA_HEADER_EXPORT template<> std::list<std::string> PayloadEntryProxy::get();
IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get();
*/
//}}} //}}}
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -32,9 +32,9 @@ ...@@ -32,9 +32,9 @@
*/ */
/** /**
* \file ipaaca-json.h * \file ipaaca-string_utils.h
* *
* \brief Header file for JSON tests. [superfluous] * \brief Header file for data and exception types and helper functions.
* *
* Users should not include this file directly, but use ipaaca.h * Users should not include this file directly, but use ipaaca.h
* *
...@@ -42,20 +42,21 @@ ...@@ -42,20 +42,21 @@
* \date March, 2015 * \date March, 2015
*/ */
#ifndef __ipaaca_json_H__ #ifndef __ipaaca_string_utils_h_INCLUDED__
#define __ipaaca_json_H__ #define __ipaaca_string_utils_h_INCLUDED__
#include "rapidjson/document.h" #ifndef __ipaaca_h_INCLUDED__
#include "rapidjson/prettywriter.h" #error "Please do not include this file directly, use ipaaca.h instead"
#include "rapidjson/filestream.h" #endif
#include <cstdio>
// Notes: // in ipaaca-string-utils.cc
// - From http://stackoverflow.com/questions/10426924/json-root-element // additional misc functions ( String splitting / joining )//{{{
// Actually there are two different JSON specifications. RFC 4627 requires a JSON text to be IPAACA_HEADER_EXPORT std::string str_trim(const std::string &s);
// an object or an array. ECMA-262, 5th edition, section 15.12 does not impose this restriction. 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
#endif // __IPAACA_JSON_H__
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -44,10 +44,19 @@ ...@@ -44,10 +44,19 @@
/** /**
\mainpage Documentation for IPAACA-C++ \mainpage Documentation for IPAACA-C++
This is the automatically generated documentation for the C++ implementation of IPAACA. This is the automatically generated documentation for the C++ implementation of IPAACA.
List of most relevant entry points: 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 Buffers: InputBuffer, OutputBuffer
...@@ -56,44 +65,113 @@ IUs: IUInterface, IU, Message ...@@ -56,44 +65,113 @@ IUs: IUInterface, IU, Message
IU handling (user-set): #IUEventHandlerFunction IU handling (user-set): #IUEventHandlerFunction
IU payload contents: Payload, PayloadEntryProxy 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__ #ifndef __ipaaca_h_INCLUDED__
#define __ipaaca_h_INCLUDED__ #define __ipaaca_h_INCLUDED__
/// ipaaca/IU/RSB protocol major version number /// ipaaca/IU/RSB protocol major version number
#define IPAACA_PROTOCOL_VERSION_MAJOR 2 #define IPAACA_PROTOCOL_VERSION_MAJOR 4
/// ipaaca/IU/RSB protocol minor version number /// 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++ /// running release number of ipaaca-c++
#define IPAACA_CPP_RELEASE_NUMBER 12 #define IPAACA_CPP_RELEASE_NUMBER 17
/// date of last release number increment /// date of last release number increment
#define IPAACA_CPP_RELEASE_DATE "2015-01-15" #define IPAACA_CPP_RELEASE_DATE "2019-02-14"
#ifndef __FUNCTION_NAME__ #ifndef __FUNCTION_NAME__
#ifdef WIN32 // Windows #if _WIN32 || _WIN64 // Windows
#define __FUNCTION_NAME__ __FUNCTION__ #define __FUNCTION_NAME__ __FUNCTION__
#else // POSIX #else // POSIX
#define __FUNCTION_NAME__ __func__ #define __FUNCTION_NAME__ __func__
#endif #endif
#endif #endif
#ifdef WIN32 #if _WIN32 || _WIN64
#define IPAACA_SYSTEM_DEPENDENT_CLASS_NAME(c) "class "##c #define IPAACA_SYSTEM_DEPENDENT_CLASS_NAME(c) "class "##c
#else #else
#define IPAACA_SYSTEM_DEPENDENT_CLASS_NAME(c) c #define IPAACA_SYSTEM_DEPENDENT_CLASS_NAME(c) c
#endif #endif
#ifdef WIN32 #if _WIN32 || _WIN64
#if defined(ipaaca_EXPORTS) #if defined(IPAACA_STATIC_BINARY)
#define IPAACA_EXPORT #define IPAACA_EXPORT
#define IPAACA_HEADER_EXPORT __declspec(dllexport) #define IPAACA_HEADER_EXPORT
#define IPAACA_MEMBER_VAR_EXPORT #define IPAACA_MEMBER_VAR_EXPORT
#else #else
#define IPAACA_EXPORT #if defined(ipaaca_EXPORTS)
#define IPAACA_HEADER_EXPORT __declspec(dllimport) #define IPAACA_EXPORT
#define IPAACA_MEMBER_VAR_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 #endif
#else #else
#define IPAACA_EXPORT #define IPAACA_EXPORT
...@@ -101,41 +179,42 @@ IU payload contents: Payload, PayloadEntryProxy ...@@ -101,41 +179,42 @@ IU payload contents: Payload, PayloadEntryProxy
#define IPAACA_MEMBER_VAR_EXPORT #define IPAACA_MEMBER_VAR_EXPORT
#endif #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 #ifdef IPAACA_DEBUG_MESSAGES
#define IPAACA_DEBUG(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_DEBUG) { std::cout << __FILE__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- Debug: " << i << std::endl; } // Full debug messages mode
#define IPAACA_INFO(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_INFO) { std::cout << __FILE__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- Info: " << i << std::endl; } #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_WARNING(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_WARNING) { std::cout << __FILE__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- WARNING: " << i << 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_ERROR(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_ERROR) { std::cout << __FILE__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- ERROR: " << i << 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; }
#define IPAACA_CRITICAL(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_CRITICAL) { std::cout << __FILE__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- CRITICAL: " << i << std::endl; }
#define IPAACA_IMPLEMENT_ME if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_INFO) { std::cout << __FILE__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- IMPLEMENT_ME:" << std::endl; }
#define IPAACA_TODO(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_INFO) { std::cout << __FILE__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- TODO: " << i << std::endl; }
#else #else
#define IPAACA_DEBUG(i) ; #define IPAACA_DEBUG(i) ;
#define IPAACA_INFO(i) ;
#define IPAACA_WARNING(i) ;
#define IPAACA_ERROR(i) ;
#define IPAACA_CRITICAL(i) ;
#define IPAACA_IMPLEMENT_ME ; #define IPAACA_IMPLEMENT_ME ;
#define IPAACA_TODO(i) ; #define IPAACA_TODO(i) ;
#endif #endif
// Always compile in info and above, even if debug messages disabled.
#ifdef IPAACA_EXPOSE_FULL_RSB_API // You can set __ipaaca_static_option_log_level (e.g. IPAACA_LOG_LEVEL_NONE for silence).
#include <rsc/runtime/TypeStringTools.h> #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; }
#include <rsb/Factory.h> #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; }
#include <rsb/Handler.h> #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; }
#include <rsb/Event.h> #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; }
#include <rsb/ParticipantConfig.h>
#include <rsb/converter/Repository.h>
#include <rsb/converter/ProtocolBufferConverter.h>
#include <rsb/converter/Converter.h>
#include <rsb/rsbexports.h>
#endif
// new json-based payload API, used in several classes // new json-based payload API, used in several classes
#define RAPIDJSON_HAS_STDSTRING 1 #define RAPIDJSON_HAS_STDSTRING 1
#include "rapidjson/document.h" #include "rapidjson/document.h"
#include "rapidjson/prettywriter.h" #include "rapidjson/prettywriter.h"
#include "rapidjson/filestream.h" #include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include <cstdio> #include <cstdio>
/// marking pure virtual functions for extra readability /// marking pure virtual functions for extra readability
...@@ -151,22 +230,29 @@ IU payload contents: Payload, PayloadEntryProxy ...@@ -151,22 +230,29 @@ IU payload contents: Payload, PayloadEntryProxy
#include <iostream> #include <iostream>
#include <fstream>
// for logger // for logger
#include <iomanip> #include <iomanip>
#ifdef WIN32 #if _WIN32 || _WIN64
// for Windows // for Windows
// time
#include <time.h> #include <time.h>
// and env
#define IPAACA_SETENV(k, v) _putenv_s(k, v);
#else #else
// for Linux and OS X // for Linux and MacOS
// time
#include <sys/time.h> #include <sys/time.h>
// and env
#define IPAACA_SETENV(k, v) setenv(k, v, 1);
#endif #endif
#include <cstdlib> #include <cstdlib>
#ifdef WIN32 #if _WIN32 || _WIN64
#include <rpc.h> #include <rpc.h>
#else #else
#include <uuid/uuid.h> #include <uuid/uuid.h>
...@@ -175,12 +261,12 @@ IU payload contents: Payload, PayloadEntryProxy ...@@ -175,12 +261,12 @@ IU payload contents: Payload, PayloadEntryProxy
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
#include <boost/bind.hpp> #include <memory>
#include <boost/function.hpp> #include <functional>
#include <boost/shared_ptr.hpp> #include <chrono>
#include <boost/weak_ptr.hpp> #include <thread>
#include <boost/pointer_cast.hpp> #include <mutex>
#include <boost/lexical_cast.hpp> #include <condition_variable>
#endif #endif
...@@ -196,8 +282,11 @@ namespace ipaaca { ...@@ -196,8 +282,11 @@ namespace ipaaca {
#include <ipaaca/ipaaca-definitions.h> #include <ipaaca/ipaaca-definitions.h>
#include <ipaaca/ipaaca-forwards.h> #include <ipaaca/ipaaca-forwards.h>
#include <ipaaca/ipaaca-errors.h>
#include <ipaaca/ipaaca-initializer.h>
#include <ipaaca/ipaaca-locking.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) // Global static library variables (run-time default configuration)
// Actual initial values are set in ipaaca.cc // Actual initial values are set in ipaaca.cc
...@@ -209,25 +298,47 @@ IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_default_chann ...@@ -209,25 +298,47 @@ IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_default_chann
/// 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 /// 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; 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(); 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; } #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 #else
// use normal gettimeofday() on POSIX // 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; } #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 #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-payload.h>
#include <ipaaca/ipaaca-buffers.h> #include <ipaaca/ipaaca-buffers.h>
#include <ipaaca/ipaaca-ius.h> #include <ipaaca/ipaaca-ius.h>
/// Full API (including RSB transport) is only exposed during
/// ipaaca compilation, user programs should use abstract API.
#ifdef IPAACA_EXPOSE_FULL_RSB_API
#include <ipaaca/ipaaca-internal.h>
#endif
} // of namespace ipaaca } // of namespace ipaaca
......
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2013 Sociable Agents Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* CITEC, Bielefeld University * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
* *
* http://opensource.cit-ec.de/projects/ipaaca/ * http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca * http://purl.org/net/ipaaca
...@@ -66,8 +67,8 @@ class ComponentNotifier { ...@@ -66,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);
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); 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: 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 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 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, ipaaca::OutputBuffer::ptr out_buf, ipaaca::InputBuffer::ptr in_buf);
public: public:
~ComponentNotifier(); ~ComponentNotifier();
protected: protected:
...@@ -90,7 +91,7 @@ class ComponentNotifier { ...@@ -90,7 +91,7 @@ class ComponentNotifier {
std::string send_categories; std::string send_categories;
std::string recv_categories; std::string recv_categories;
public: public:
typedef boost::shared_ptr<ComponentNotifier> ptr; typedef std::shared_ptr<ComponentNotifier> ptr;
}; };
......
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights // Licensed under the MIT License (the "License"); you may not use this file except
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // in compliance with the License. You may obtain a copy of the License at
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: // http://opensource.org/licenses/MIT
// //
// The above copyright notice and this permission notice shall be included in // Unless required by applicable law or agreed to in writing, software distributed
// all copies or substantial portions of the Software. // 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
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // specific language governing permissions and limitations under the License.
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #ifndef RAPIDJSON_ALLOCATORS_H_
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #define RAPIDJSON_ALLOCATORS_H_
// 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 #include "rapidjson.h"
// THE SOFTWARE. #include "internal/meta.h"
#ifndef RAPIDJSON_ALLOCATORS_H_ #include <memory>
#define RAPIDJSON_ALLOCATORS_H_
#if RAPIDJSON_HAS_CXX11
#include "rapidjson.h" #include <type_traits>
#endif
RAPIDJSON_NAMESPACE_BEGIN
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Allocator ///////////////////////////////////////////////////////////////////////////////
// Allocator
/*! \class rapidjson::Allocator
\brief Concept for allocating, resizing and freeing memory block. /*! \class rapidjson::Allocator
\brief Concept for allocating, resizing and freeing memory block.
Note that Malloc() and Realloc() are non-static but Free() is static.
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. So if an allocator need to support Free(), it needs to put its pointer in
the header of memory block.
\code
concept Allocator { \code
static const bool kNeedFree; //!< Whether this allocator needs to call Free(). 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. // Allocate a memory block.
// \returns pointer to the memory block. // \param size of the memory block in bytes.
void* Malloc(size_t size); // \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. // Resize a memory block.
// \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 originalPtr The pointer to current memory block. Null pointer is permitted.
// \param newSize the new size in bytes. // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); // \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. // Free a memory block.
static void Free(void *ptr); // \param pointer to the memory block. Null pointer is permitted.
}; static void Free(void *ptr);
\endcode };
*/ \endcode
*/
///////////////////////////////////////////////////////////////////////////////
// CrtAllocator
/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
//! C-runtime library allocator. \ingroup RAPIDJSON_CONFIG
/*! This class is just wrapper for standard C library memory routines. \brief User-defined kDefaultChunkCapacity definition.
\note implements Allocator concept
*/ User can define this as any \c size that is a power of 2.
class CrtAllocator { */
public:
static const bool kNeedFree = true; #ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
void* Malloc(size_t size) { return std::malloc(size); } #define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return std::realloc(originalPtr, newSize); } #endif
static void Free(void *ptr) { std::free(ptr); }
};
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// // CrtAllocator
// MemoryPoolAllocator
//! C-runtime library allocator.
//! Default memory allocator used by the parser and DOM. /*! This class is just wrapper for standard C library memory routines.
/*! This allocator allocate memory blocks from pre-allocated memory chunks. \note implements Allocator concept
*/
It does not free memory blocks. And Realloc() only allocate new memory. class CrtAllocator {
public:
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. static const bool kNeedFree = true;
void* Malloc(size_t size) {
User may also supply a buffer as the first chunk. if (size) // behavior of malloc(0) is implementation defined.
return RAPIDJSON_MALLOC(size);
If the user-buffer is full then additional chunks are allocated by BaseAllocator. else
return NULL; // standardize to returning NULL.
The user-buffer is not deallocated by this allocator. }
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. (void)originalSize;
\note implements Allocator concept if (newSize == 0) {
*/ RAPIDJSON_FREE(originalPtr);
template <typename BaseAllocator = CrtAllocator> return NULL;
class MemoryPoolAllocator { }
public: return RAPIDJSON_REALLOC(originalPtr, newSize);
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) }
static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }
//! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
\param baseAllocator The allocator for allocating memory chunks. return true;
*/ }
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) return false;
{ }
} };
//! Constructor with user-supplied buffer. ///////////////////////////////////////////////////////////////////////////////
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. // MemoryPoolAllocator
The user buffer will not be deallocated when this allocator is destructed. //! Default memory allocator used by the parser and DOM.
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
\param buffer User supplied buffer.
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). It does not free memory blocks. And Realloc() only allocate new memory.
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks. The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
*/
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : User may also supply a buffer as the first chunk.
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{ If the user-buffer is full then additional chunks are allocated by BaseAllocator.
RAPIDJSON_ASSERT(buffer != 0);
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); The user-buffer is not deallocated by this allocator.
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
chunkHead_->capacity = size - sizeof(ChunkHeader); \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
chunkHead_->size = 0; \note implements Allocator concept
chunkHead_->next = 0; */
} template <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator {
//! Destructor. //! Chunk header for perpending to each chunk.
/*! This deallocates all memory chunks, excluding the user-supplied buffer. /*! Chunks are stored as a singly linked list.
*/ */
~MemoryPoolAllocator() { struct ChunkHeader {
Clear(); size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
RAPIDJSON_DELETE(ownBaseAllocator_); size_t size; //!< Current size of allocated memory in bytes.
} ChunkHeader *next; //!< Next chunk in the linked list.
};
//! Deallocates all memory chunks, excluding the user-supplied buffer.
void Clear() { struct SharedData {
while(chunkHead_ != 0 && chunkHead_ != userBuffer_) { ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
ChunkHeader* next = chunkHead_->next; BaseAllocator* ownBaseAllocator; //!< base allocator created by this object.
baseAllocator_->Free(chunkHead_); size_t refcount;
chunkHead_ = next; bool ownBuffer;
} };
}
static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData));
//! Computes the total capacity of allocated memory chunks. static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader));
/*! \return total capacity in bytes.
*/ static inline ChunkHeader *GetChunkHead(SharedData *shared)
size_t Capacity() const { {
size_t capacity = 0; return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) }
capacity += c->capacity; static inline uint8_t *GetChunkBuffer(SharedData *shared)
return capacity; {
} return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER;
}
//! Computes the memory blocks allocated.
/*! \return total used bytes. static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
*/
size_t Size() const { public:
size_t size = 0; static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy
size += c->size;
return size; //! Constructor with chunkSize.
} /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
//! Allocates a memory block. (concept Allocator) */
void* Malloc(size_t size) { explicit
size = RAPIDJSON_ALIGN(size); MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) chunk_capacity_(chunkSize),
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0))
void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size; {
chunkHead_->size += size; RAPIDJSON_ASSERT(baseAllocator_ != 0);
return buffer; RAPIDJSON_ASSERT(shared_ != 0);
} if (baseAllocator) {
shared_->ownBaseAllocator = 0;
//! Resizes a memory block (concept Allocator) }
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { else {
if (originalPtr == 0) shared_->ownBaseAllocator = baseAllocator_;
return Malloc(newSize); }
shared_->chunkHead = GetChunkHead(shared_);
// Do not shrink if new size is smaller than original shared_->chunkHead->capacity = 0;
if (originalSize >= newSize) shared_->chunkHead->size = 0;
return originalPtr; shared_->chunkHead->next = 0;
shared_->ownBuffer = true;
// Simply expand it if it is the last allocation and there is sufficient space shared_->refcount = 1;
if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) { }
size_t increment = static_cast<size_t>(newSize - originalSize);
increment = RAPIDJSON_ALIGN(increment); //! Constructor with user-supplied buffer.
if (chunkHead_->size + increment <= chunkHead_->capacity) { /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
chunkHead_->size += increment;
return originalPtr; 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).
// Realloc process: allocate and copy memory, do not free original buffer. \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
void* newBuffer = Malloc(newSize); \param baseAllocator The allocator for allocating memory chunks.
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. */
return std::memcpy(newBuffer, originalPtr, originalSize); MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
} chunk_capacity_(chunkSize),
baseAllocator_(baseAllocator),
//! Frees a memory block (concept Allocator) shared_(static_cast<SharedData*>(AlignBuffer(buffer, size)))
static void Free(void *ptr) { (void)ptr; } // Do nothing {
RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER);
private: shared_->chunkHead = GetChunkHead(shared_);
//! Copy constructor is not permitted. shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER;
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; shared_->chunkHead->size = 0;
//! Copy assignment operator is not permitted. shared_->chunkHead->next = 0;
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; shared_->ownBaseAllocator = 0;
shared_->ownBuffer = false;
//! Creates a new chunk. shared_->refcount = 1;
/*! \param capacity Capacity of the chunk in bytes. }
*/
void AddChunk(size_t capacity) { MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT :
if (!baseAllocator_) chunk_capacity_(rhs.chunk_capacity_),
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); baseAllocator_(rhs.baseAllocator_),
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity)); shared_(rhs.shared_)
chunk->capacity = capacity; {
chunk->size = 0; RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
chunk->next = chunkHead_; ++shared_->refcount;
chunkHead_ = chunk; }
} MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT
{
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
++rhs.shared_->refcount;
//! Chunk header for perpending to each chunk. this->~MemoryPoolAllocator();
/*! Chunks are stored as a singly linked list. baseAllocator_ = rhs.baseAllocator_;
*/ chunk_capacity_ = rhs.chunk_capacity_;
struct ChunkHeader { shared_ = rhs.shared_;
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). return *this;
size_t size; //!< Current size of allocated memory in bytes. }
ChunkHeader *next; //!< Next chunk in the linked list.
}; #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT :
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. chunk_capacity_(rhs.chunk_capacity_),
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. baseAllocator_(rhs.baseAllocator_),
void *userBuffer_; //!< User supplied buffer. shared_(rhs.shared_)
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. {
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
}; rhs.shared_ = 0;
}
RAPIDJSON_NAMESPACE_END MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT
{
#endif // RAPIDJSON_ENCODINGS_H_ 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_
Source diff could not be displayed: it is too large. Options to address this: view the blob.
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights // Licensed under the MIT License (the "License"); you may not use this file except
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // in compliance with the License. You may obtain a copy of the License at
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: // http://opensource.org/licenses/MIT
// //
// The above copyright notice and this permission notice shall be included in // Unless required by applicable law or agreed to in writing, software distributed
// all copies or substantial portions of the Software. // 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
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // specific language governing permissions and limitations under the License.
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #ifndef RAPIDJSON_ENCODEDSTREAM_H_
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #define RAPIDJSON_ENCODEDSTREAM_H_
// 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 #include "stream.h"
// THE SOFTWARE. #include "memorystream.h"
#ifndef RAPIDJSON_ENCODEDSTREAM_H_ #ifdef __GNUC__
#define RAPIDJSON_ENCODEDSTREAM_H_ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#include "rapidjson.h" #endif
#ifdef __GNUC__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(padded)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
//! Input byte stream wrapper with a statically bound encoding. //! 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 Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
\tparam InputByteStream Type of input byte stream. For example, FileReadStream. \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
*/ */
template <typename Encoding, typename InputByteStream> template <typename Encoding, typename InputByteStream>
class EncodedInputStream { class EncodedInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public: public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
EncodedInputStream(InputByteStream& is) : is_(is) { EncodedInputStream(InputByteStream& is) : is_(is) {
current_ = Encoding::TakeBOM(is_); current_ = Encoding::TakeBOM(is_);
} }
Ch Peek() const { return current_; } Ch Peek() const { return current_; }
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
size_t Tell() const { return is_.Tell(); } size_t Tell() const { return is_.Tell(); }
// Not implemented // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private: private:
EncodedInputStream(const EncodedInputStream&); EncodedInputStream(const EncodedInputStream&);
EncodedInputStream& operator=(const EncodedInputStream&); EncodedInputStream& operator=(const EncodedInputStream&);
InputByteStream& is_; InputByteStream& is_;
Ch current_; Ch current_;
}; };
//! Output byte stream wrapper with statically bound encoding. //! Specialized for UTF8 MemoryStream.
/*! template <>
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. class EncodedInputStream<UTF8<>, MemoryStream> {
\tparam InputByteStream Type of input byte stream. For example, FileWriteStream. public:
*/ typedef UTF8<>::Ch Ch;
template <typename Encoding, typename OutputByteStream>
class EncodedOutputStream { EncodedInputStream(MemoryStream& is) : is_(is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
public: if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
typedef typename Encoding::Ch Ch; if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
}
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { Ch Peek() const { return is_.Peek(); }
if (putBOM) Ch Take() { return is_.Take(); }
Encoding::PutBOM(os_); size_t Tell() const { return is_.Tell(); }
}
// Not implemented
void Put(Ch c) { Encoding::Put(os_, c); } void Put(Ch) {}
void Flush() { os_.Flush(); } void Flush() {}
Ch* PutBegin() { return 0; }
// Not implemented size_t PutEnd(Ch*) { return 0; }
Ch Peek() const { RAPIDJSON_ASSERT(false); }
Ch Take() { RAPIDJSON_ASSERT(false); } MemoryStream& is_;
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } private:
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } EncodedInputStream(const EncodedInputStream&);
EncodedInputStream& operator=(const EncodedInputStream&);
private: };
EncodedOutputStream(const EncodedOutputStream&);
EncodedOutputStream& operator=(const EncodedOutputStream&); //! Output byte stream wrapper with statically bound encoding.
/*!
OutputByteStream& os_; \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.
*/
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x template <typename Encoding, typename OutputByteStream>
class EncodedOutputStream {
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
/*! public:
\tparam CharType Type of character for reading. typedef typename Encoding::Ch Ch;
\tparam InputByteStream type of input byte stream to be wrapped.
*/ EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
template <typename CharType, typename InputByteStream> if (putBOM)
class AutoUTFInputStream { Encoding::PutBOM(os_);
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); }
public:
typedef CharType Ch; void Put(Ch c) { Encoding::Put(os_, c); }
void Flush() { os_.Flush(); }
//! Constructor.
/*! // Not implemented
\param is input stream to be wrapped. Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
\param type UTF encoding type if it is not detected from the stream. Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
*/ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
DetectType(); size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
takeFunc_ = f[type_]; private:
current_ = takeFunc_(*is_); EncodedOutputStream(const EncodedOutputStream&);
} EncodedOutputStream& operator=(const EncodedOutputStream&);
UTFType GetType() const { return type_; } OutputByteStream& os_;
bool HasBOM() const { return hasBOM_; } };
Ch Peek() const { return current_; } #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
size_t Tell() const { return is_->Tell(); } //! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
// Not implemented \tparam CharType Type of character for reading.
void Put(Ch) { RAPIDJSON_ASSERT(false); } \tparam InputByteStream type of input byte stream to be wrapped.
void Flush() { RAPIDJSON_ASSERT(false); } */
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } template <typename CharType, typename InputByteStream>
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } class AutoUTFInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
private: public:
AutoUTFInputStream(const AutoUTFInputStream&); typedef CharType Ch;
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
//! Constructor.
// Detect encoding type with BOM or RFC 4627 /*!
void DetectType() { \param is input stream to be wrapped.
// BOM (Byte Order Mark): \param type UTF encoding type if it is not detected from the stream.
// 00 00 FE FF UTF-32BE */
// FF FE 00 00 UTF-32LE AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
// FE FF UTF-16BE RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
// FF FE UTF-16LE DetectType();
// EF BB BF UTF-8 static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
takeFunc_ = f[type_];
const unsigned char* c = (const unsigned char *)is_->Peek4(); current_ = takeFunc_(*is_);
if (!c) }
return;
UTFType GetType() const { return type_; }
unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); bool HasBOM() const { return hasBOM_; }
hasBOM_ = false;
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } Ch Peek() const { return current_; }
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } size_t Tell() const { return is_->Tell(); }
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(); } // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
// RFC 4627: Section 3 void Flush() { RAPIDJSON_ASSERT(false); }
// "Since the first two characters of a JSON text will always be ASCII Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
// characters [RFC0020], it is possible to determine whether an octet size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// 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." private:
// 00 00 00 xx UTF-32BE AutoUTFInputStream(const AutoUTFInputStream&);
// 00 xx 00 xx UTF-16BE AutoUTFInputStream& operator=(const AutoUTFInputStream&);
// xx 00 00 00 UTF-32LE
// xx 00 xx 00 UTF-16LE // Detect encoding type with BOM or RFC 4627
// xx xx xx xx UTF-8 void DetectType() {
// BOM (Byte Order Mark):
if (!hasBOM_) { // 00 00 FE FF UTF-32BE
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); // FF FE 00 00 UTF-32LE
switch (pattern) { // FE FF UTF-16BE
case 0x08: type_ = kUTF32BE; break; // FF FE UTF-16LE
case 0x0A: type_ = kUTF16BE; break; // EF BB BF UTF-8
case 0x01: type_ = kUTF32LE; break;
case 0x05: type_ = kUTF16LE; break; const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
case 0x0F: type_ = kUTF8; break; if (!c)
default: break; // Use type defined by user. return;
}
} unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
hasBOM_ = false;
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion. if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
switch (type_) { else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
case kUTF8: else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
// Do nothing else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
break; else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
case kUTF16LE:
case kUTF16BE: // RFC 4627: Section 3
RAPIDJSON_ASSERT(sizeof(Ch) >= 2); // "Since the first two characters of a JSON text will always be ASCII
break; // characters [RFC0020], it is possible to determine whether an octet
case kUTF32LE: // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
case kUTF32BE: // at the pattern of nulls in the first four octets."
RAPIDJSON_ASSERT(sizeof(Ch) >= 4); // 00 00 00 xx UTF-32BE
break; // 00 xx 00 xx UTF-16BE
default: // xx 00 00 00 UTF-32LE
RAPIDJSON_ASSERT(false); // Invalid type // xx 00 xx 00 UTF-16LE
} // xx xx xx xx UTF-8
}
if (!hasBOM_) {
typedef Ch (*TakeFunc)(InputByteStream& is); int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
InputByteStream* is_; switch (pattern) {
UTFType type_; case 0x08: type_ = kUTF32BE; break;
Ch current_; case 0x0A: type_ = kUTF16BE; break;
TakeFunc takeFunc_; case 0x01: type_ = kUTF32LE; break;
bool hasBOM_; case 0x05: type_ = kUTF16LE; break;
}; case 0x0F: type_ = kUTF8; break;
default: break; // Use type defined by user.
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. }
/*! }
\tparam CharType Type of character for writing.
\tparam InputByteStream type of output byte stream to be wrapped. // 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);
template <typename CharType, typename OutputByteStream> if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
class AutoUTFOutputStream { }
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public: typedef Ch (*TakeFunc)(InputByteStream& is);
typedef CharType Ch; InputByteStream* is_;
UTFType type_;
//! Constructor. Ch current_;
/*! TakeFunc takeFunc_;
\param os output stream to be wrapped. bool hasBOM_;
\param type UTF encoding type. };
\param putBOM Whether to write BOM at the beginning of the stream.
*/ //! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { /*!
// RUntime check whether the size of character type is sufficient. It only perform checks with assertion. \tparam CharType Type of character for writing.
switch (type_) { \tparam OutputByteStream type of output byte stream to be wrapped.
case kUTF16LE: */
case kUTF16BE: template <typename CharType, typename OutputByteStream>
RAPIDJSON_ASSERT(sizeof(Ch) >= 2); class AutoUTFOutputStream {
break; RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
case kUTF32LE: public:
case kUTF32BE: typedef CharType Ch;
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
break; //! Constructor.
case kUTF8: /*!
// Do nothing \param os output stream to be wrapped.
break; \param type UTF encoding type.
default: \param putBOM Whether to write BOM at the beginning of the stream.
RAPIDJSON_ASSERT(false); // Invalid UTFType */
} AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
putFunc_ = f[type_]; // 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 (putBOM) if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
PutBOM();
} static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
putFunc_ = f[type_];
UTFType GetType() const { return type_; }
if (putBOM)
void Put(Ch c) { putFunc_(*os_, c); } PutBOM();
void Flush() { os_->Flush(); } }
// Not implemented UTFType GetType() const { return type_; }
Ch Peek() const { RAPIDJSON_ASSERT(false); }
Ch Take() { RAPIDJSON_ASSERT(false); } void Put(Ch c) { putFunc_(*os_, c); }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } void Flush() { os_->Flush(); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
private: Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
AutoUTFOutputStream(const AutoUTFOutputStream&); size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
void PutBOM() {
typedef void (*PutBOMFunc)(OutputByteStream&); private:
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; AutoUTFOutputStream(const AutoUTFOutputStream&);
f[type_](*os_); AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
}
void PutBOM() {
typedef void (*PutFunc)(OutputByteStream&, Ch); typedef void (*PutBOMFunc)(OutputByteStream&);
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
OutputByteStream* os_; f[type_](*os_);
UTFType type_; }
PutFunc putFunc_;
}; typedef void (*PutFunc)(OutputByteStream&, Ch);
#undef RAPIDJSON_ENCODINGS_FUNC OutputByteStream* os_;
UTFType type_;
RAPIDJSON_NAMESPACE_END PutFunc putFunc_;
};
#ifdef __GNUC__
RAPIDJSON_DIAG_POP #undef RAPIDJSON_ENCODINGS_FUNC
#endif
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_FILESTREAM_H_
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_FILESTREAM_H_
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights // Licensed under the MIT License (the "License"); you may not use this file except
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // in compliance with the License. You may obtain a copy of the License at
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: // http://opensource.org/licenses/MIT
// //
// The above copyright notice and this permission notice shall be included in // Unless required by applicable law or agreed to in writing, software distributed
// all copies or substantial portions of the Software. // 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
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // specific language governing permissions and limitations under the License.
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #ifndef RAPIDJSON_ENCODINGS_H_
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #define RAPIDJSON_ENCODINGS_H_
// 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 #include "rapidjson.h"
// THE SOFTWARE.
#if defined(_MSC_VER) && !defined(__clang__)
#ifndef RAPIDJSON_ENCODINGS_H_ RAPIDJSON_DIAG_PUSH
#define RAPIDJSON_ENCODINGS_H_ RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
RAPIDJSON_DIAG_OFF(4702) // unreachable code
#include "rapidjson.h" #elif defined(__GNUC__)
RAPIDJSON_DIAG_PUSH
#ifdef _MSC_VER RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(overflow)
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data #endif
RAPIDJSON_DIAG_OFF(4702) // unreachable code
#elif defined(__GNUC__) RAPIDJSON_NAMESPACE_BEGIN
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) ///////////////////////////////////////////////////////////////////////////////
#endif // Encoding
RAPIDJSON_NAMESPACE_BEGIN /*! \class rapidjson::Encoding
\brief Concept for encoding of Unicode characters.
///////////////////////////////////////////////////////////////////////////////
// Encoding \code
concept Encoding {
/*! \class rapidjson::Encoding typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
\brief Concept for encoding of Unicode characters.
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
\code
concept Encoding { //! \brief Encode a Unicode codepoint to an output stream.
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. //! \param os Output stream.
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
enum { supportUnicode = 1 }; // or 0 if not supporting unicode template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint);
//! \brief Encode a Unicode codepoint to an output stream.
//! \param os Output stream. //! \brief Decode a Unicode codepoint from an input stream.
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. //! \param is Input stream.
template<typename OutputStream> //! \param codepoint Output of the unicode codepoint.
static void Encode(OutputStream& os, unsigned codepoint); //! \return true if a valid codepoint can be decoded from the stream.
template <typename InputStream>
//! \brief Decode a Unicode codepoint from an input stream. static bool Decode(InputStream& is, unsigned* codepoint);
//! \param is Input stream.
//! \param codepoint Output of the unicode codepoint. //! \brief Validate one Unicode codepoint from an encoded stream.
//! \return true if a valid codepoint can be decoded from the stream. //! \param is Input stream to obtain codepoint.
template <typename InputStream> //! \param os Output for copying one codepoint.
static bool Decode(InputStream& is, unsigned* codepoint); //! \return true if it is valid.
//! \note This function just validating and copying the codepoint without actually decode it.
//! \brief Validate one Unicode codepoint from an encoded stream. template <typename InputStream, typename OutputStream>
//! \param is Input stream to obtain codepoint. static bool Validate(InputStream& is, OutputStream& os);
//! \param os Output for copying one codepoint.
//! \return true if it is valid. // The following functions are deal with byte streams.
//! \note This function just validating and copying the codepoint without actually decode it.
template <typename InputStream, typename OutputStream> //! Take a character from input byte stream, skip BOM if exist.
static bool Validate(InputStream& is, OutputStream& os); template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is);
// The following functions are deal with byte streams.
//! Take a character from input byte stream.
//! Take a character from input byte stream, skip BOM if exist. template <typename InputByteStream>
template <typename InputByteStream> static Ch Take(InputByteStream& is);
static CharType TakeBOM(InputByteStream& is);
//! Put BOM to output byte stream.
//! Take a character from input byte stream. template <typename OutputByteStream>
template <typename InputByteStream> static void PutBOM(OutputByteStream& os);
static Ch Take(InputByteStream& is);
//! Put a character to output byte stream.
//! Put BOM to output byte stream. template <typename OutputByteStream>
template <typename OutputByteStream> static void Put(OutputByteStream& os, Ch c);
static void PutBOM(OutputByteStream& os); };
\endcode
//! Put a character to output byte stream. */
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c); ///////////////////////////////////////////////////////////////////////////////
}; // UTF8
\endcode
*/ //! UTF-8 encoding.
/*! http://en.wikipedia.org/wiki/UTF-8
/////////////////////////////////////////////////////////////////////////////// http://tools.ietf.org/html/rfc3629
// UTF8 \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
\note implements Encoding concept
//! UTF-8 encoding. */
/*! http://en.wikipedia.org/wiki/UTF-8 template<typename CharType = char>
http://tools.ietf.org/html/rfc3629 struct UTF8 {
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. typedef CharType Ch;
\note implements Encoding concept
*/ enum { supportUnicode = 1 };
template<typename CharType = char>
struct UTF8 { template<typename OutputStream>
typedef CharType Ch; static void Encode(OutputStream& os, unsigned codepoint) {
if (codepoint <= 0x7F)
enum { supportUnicode = 1 }; os.Put(static_cast<Ch>(codepoint & 0xFF));
else if (codepoint <= 0x7FF) {
template<typename OutputStream> os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
static void Encode(OutputStream& os, unsigned codepoint) { os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
if (codepoint <= 0x7F) }
os.Put(static_cast<Ch>(codepoint & 0xFF)); else if (codepoint <= 0xFFFF) {
else if (codepoint <= 0x7FF) { os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF))); os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F)))); os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
} }
else if (codepoint <= 0xFFFF) { else {
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF))); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F))); os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F))); os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
} os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
else { os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
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))); template<typename OutputStream>
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F))); static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
} if (codepoint <= 0x7F)
} PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
else if (codepoint <= 0x7FF) {
template <typename InputStream> PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
static bool Decode(InputStream& is, unsigned* codepoint) { PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu) }
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) else if (codepoint <= 0xFFFF) {
#define TAIL() COPY(); TRANS(0x70) PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
Ch c = is.Take(); PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
if (!(c & 0x80)) { PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
*codepoint = (unsigned char)c; }
return true; else {
} RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
unsigned char type = GetRange((unsigned char)c); PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
*codepoint = (0xFF >> type) & (unsigned char)c; PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
bool result = true; PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
switch (type) { }
case 2: TAIL(); return result; }
case 3: TAIL(); TAIL(); return result;
case 4: COPY(); TRANS(0x50); TAIL(); return result; template <typename InputStream>
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; static bool Decode(InputStream& is, unsigned* codepoint) {
case 6: TAIL(); TAIL(); TAIL(); return result; #define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
case 10: COPY(); TRANS(0x20); TAIL(); return result; #define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; #define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
default: return false; typename InputStream::Ch c = is.Take();
} if (!(c & 0x80)) {
#undef COPY *codepoint = static_cast<unsigned char>(c);
#undef TRANS return true;
#undef TAIL }
}
unsigned char type = GetRange(static_cast<unsigned char>(c));
template <typename InputStream, typename OutputStream> if (type >= 32) {
static bool Validate(InputStream& is, OutputStream& os) { *codepoint = 0;
#define COPY() os.Put(c = is.Take()) } else {
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) *codepoint = (0xFFu >> type) & static_cast<unsigned char>(c);
#define TAIL() COPY(); TRANS(0x70) }
Ch c; bool result = true;
COPY(); switch (type) {
if (!(c & 0x80)) case 2: RAPIDJSON_TAIL(); return result;
return true; case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
bool result = true; case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
switch (GetRange((unsigned char)c)) { case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
case 2: TAIL(); return result; case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
case 3: TAIL(); TAIL(); return result; case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
case 4: COPY(); TRANS(0x50); TAIL(); return result; default: return false;
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; }
case 6: TAIL(); TAIL(); TAIL(); return result; #undef RAPIDJSON_COPY
case 10: COPY(); TRANS(0x20); TAIL(); return result; #undef RAPIDJSON_TRANS
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; #undef RAPIDJSON_TAIL
default: return false; }
}
#undef COPY template <typename InputStream, typename OutputStream>
#undef TRANS static bool Validate(InputStream& is, OutputStream& os) {
#undef TAIL #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)
static unsigned char GetRange(unsigned char c) { Ch c;
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ RAPIDJSON_COPY();
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. if (!(c & 0x80))
static const unsigned char type[] = { return true;
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, bool result = true;
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, switch (GetRange(static_cast<unsigned char>(c))) {
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, case 2: RAPIDJSON_TAIL(); return result;
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
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, case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
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, case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
}; default: return false;
return type[c]; }
} #undef RAPIDJSON_COPY
#undef RAPIDJSON_TRANS
template <typename InputByteStream> #undef RAPIDJSON_TAIL
static CharType TakeBOM(InputByteStream& is) { }
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
Ch c = Take(is); static unsigned char GetRange(unsigned char c) {
if ((unsigned char)c != 0xEFu) return c; // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
c = is.Take(); // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
if ((unsigned char)c != 0xBBu) return c; static const unsigned char type[] = {
c = is.Take(); 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,
if ((unsigned char)c != 0xBFu) return c; 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,
c = is.Take(); 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,
return c; 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,
template <typename InputByteStream> 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
static Ch Take(InputByteStream& is) { 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); 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,
return is.Take(); 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 OutputByteStream> }
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); template <typename InputByteStream>
os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu); static CharType TakeBOM(InputByteStream& is) {
} RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
typename InputByteStream::Ch c = Take(is);
template <typename OutputByteStream> if (static_cast<unsigned char>(c) != 0xEFu) return c;
static void Put(OutputByteStream& os, Ch c) { c = is.Take();
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); if (static_cast<unsigned char>(c) != 0xBBu) return c;
os.Put(static_cast<typename OutputByteStream::Ch>(c)); c = is.Take();
} if (static_cast<unsigned char>(c) != 0xBFu) return c;
}; c = is.Take();
return c;
/////////////////////////////////////////////////////////////////////////////// }
// UTF16
template <typename InputByteStream>
//! UTF-16 encoding. static Ch Take(InputByteStream& is) {
/*! http://en.wikipedia.org/wiki/UTF-16 RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
http://tools.ietf.org/html/rfc2781 return static_cast<Ch>(is.Take());
\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
template <typename OutputByteStream>
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. static void PutBOM(OutputByteStream& os) {
For streaming, use UTF16LE and UTF16BE, which handle endianness. RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
*/ os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
template<typename CharType = wchar_t> os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
struct UTF16 { os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
typedef CharType Ch; }
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
template <typename OutputByteStream>
enum { supportUnicode = 1 }; static void Put(OutputByteStream& os, Ch c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
template<typename OutputStream> os.Put(static_cast<typename OutputByteStream::Ch>(c));
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)); // UTF16
}
else { //! UTF-16 encoding.
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); /*! http://en.wikipedia.org/wiki/UTF-16
unsigned v = codepoint - 0x10000; http://tools.ietf.org/html/rfc2781
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800)); \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
os.Put((v & 0x3FF) | 0xDC00); \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 InputStream> */
static bool Decode(InputStream& is, unsigned* codepoint) { template<typename CharType = wchar_t>
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); struct UTF16 {
Ch c = is.Take(); typedef CharType Ch;
if (c < 0xD800 || c > 0xDFFF) { RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
*codepoint = c;
return true; enum { supportUnicode = 1 };
}
else if (c <= 0xDBFF) { template<typename OutputStream>
*codepoint = (c & 0x3FF) << 10; static void Encode(OutputStream& os, unsigned codepoint) {
c = is.Take(); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
*codepoint |= (c & 0x3FF); if (codepoint <= 0xFFFF) {
*codepoint += 0x10000; RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
return c >= 0xDC00 && c <= 0xDFFF; os.Put(static_cast<typename OutputStream::Ch>(codepoint));
} }
return false; else {
} RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000;
template <typename InputStream, typename OutputStream> os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
static bool Validate(InputStream& is, OutputStream& os) { os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); }
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); }
Ch c;
os.Put(c = is.Take());
if (c < 0xD800 || c > 0xDFFF) template<typename OutputStream>
return true; static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
else if (c <= 0xDBFF) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
os.Put(c = is.Take()); if (codepoint <= 0xFFFF) {
return c >= 0xDC00 && c <= 0xDFFF; RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
} PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
return false; }
} else {
}; RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000;
//! UTF-16 little endian encoding. PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
template<typename CharType = wchar_t> PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
struct UTF16LE : UTF16<CharType> { }
template <typename InputByteStream> }
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); template <typename InputStream>
CharType c = Take(is); static bool Decode(InputStream& is, unsigned* codepoint) {
return (unsigned short)c == 0xFEFFu ? Take(is) : c; RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
} typename InputStream::Ch c = is.Take();
if (c < 0xD800 || c > 0xDFFF) {
template <typename InputByteStream> *codepoint = static_cast<unsigned>(c);
static CharType Take(InputByteStream& is) { return true;
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); }
CharType c = (unsigned char)is.Take(); else if (c <= 0xDBFF) {
c |= (unsigned char)is.Take() << 8; *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
return c; c = is.Take();
} *codepoint |= (static_cast<unsigned>(c) & 0x3FF);
*codepoint += 0x10000;
template <typename OutputByteStream> return c >= 0xDC00 && c <= 0xDFFF;
static void PutBOM(OutputByteStream& os) { }
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); return false;
os.Put(0xFFu); os.Put(0xFEu); }
}
template <typename InputStream, typename OutputStream>
template <typename OutputByteStream> static bool Validate(InputStream& is, OutputStream& os) {
static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
os.Put(c & 0xFFu); typename InputStream::Ch c;
os.Put((c >> 8) & 0xFFu); os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
} if (c < 0xD800 || c > 0xDFFF)
}; return true;
else if (c <= 0xDBFF) {
//! UTF-16 big endian encoding. os.Put(c = is.Take());
template<typename CharType = wchar_t> return c >= 0xDC00 && c <= 0xDFFF;
struct UTF16BE : UTF16<CharType> { }
template <typename InputByteStream> return false;
static CharType TakeBOM(InputByteStream& is) { }
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); };
CharType c = Take(is);
return (unsigned short)c == 0xFEFFu ? Take(is) : c; //! UTF-16 little endian encoding.
} template<typename CharType = wchar_t>
struct UTF16LE : UTF16<CharType> {
template <typename InputByteStream> template <typename InputByteStream>
static CharType Take(InputByteStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take() << 8; CharType c = Take(is);
c |= (unsigned char)is.Take(); return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
return c; }
}
template <typename InputByteStream>
template <typename OutputByteStream> static CharType Take(InputByteStream& is) {
static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); unsigned c = static_cast<uint8_t>(is.Take());
os.Put(0xFEu); os.Put(0xFFu); c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
} return static_cast<CharType>(c);
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) { template <typename OutputByteStream>
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); static void PutBOM(OutputByteStream& os) {
os.Put((c >> 8) & 0xFFu); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(c & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
} os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
}; }
/////////////////////////////////////////////////////////////////////////////// template <typename OutputByteStream>
// UTF32 static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
//! UTF-32 encoding. os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
/*! http://en.wikipedia.org/wiki/UTF-32 os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
\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. //! UTF-16 big endian encoding.
For streaming, use UTF32LE and UTF32BE, which handle endianness. template<typename CharType = wchar_t>
*/ struct UTF16BE : UTF16<CharType> {
template<typename CharType = unsigned> template <typename InputByteStream>
struct UTF32 { static CharType TakeBOM(InputByteStream& is) {
typedef CharType Ch; RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); CharType c = Take(is);
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
enum { supportUnicode = 1 }; }
template<typename OutputStream> template <typename InputByteStream>
static void Encode(OutputStream& os, unsigned codepoint) { static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
os.Put(codepoint); c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
} return static_cast<CharType>(c);
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) { template <typename OutputByteStream>
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); static void PutBOM(OutputByteStream& os) {
Ch c = is.Take(); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
*codepoint = c; os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
return c <= 0x10FFFF; os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
} }
template <typename InputStream, typename OutputStream> template <typename OutputByteStream>
static bool Validate(InputStream& is, OutputStream& os) { static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
Ch c; os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
os.Put(c = is.Take()); os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
return c <= 0x10FFFF; }
} };
};
///////////////////////////////////////////////////////////////////////////////
//! UTF-32 little endian enocoding. // UTF32
template<typename CharType = unsigned>
struct UTF32LE : UTF32<CharType> { //! UTF-32 encoding.
template <typename InputByteStream> /*! http://en.wikipedia.org/wiki/UTF-32
static CharType TakeBOM(InputByteStream& is) { \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); \note implements Encoding concept
CharType c = Take(is);
return (unsigned)c == 0x0000FEFFu ? Take(is) : c; \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 InputByteStream> template<typename CharType = unsigned>
static CharType Take(InputByteStream& is) { struct UTF32 {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); typedef CharType Ch;
CharType c = (unsigned char)is.Take(); RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
c |= (unsigned char)is.Take() << 8;
c |= (unsigned char)is.Take() << 16; enum { supportUnicode = 1 };
c |= (unsigned char)is.Take() << 24;
return c; template<typename OutputStream>
} static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
template <typename OutputByteStream> RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
static void PutBOM(OutputByteStream& os) { os.Put(codepoint);
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); }
os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
} template<typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
template <typename OutputByteStream> RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); PutUnsafe(os, codepoint);
os.Put(c & 0xFFu); }
os.Put((c >> 8) & 0xFFu);
os.Put((c >> 16) & 0xFFu); template <typename InputStream>
os.Put((c >> 24) & 0xFFu); static bool Decode(InputStream& is, unsigned* codepoint) {
} RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
}; Ch c = is.Take();
*codepoint = c;
//! UTF-32 big endian encoding. return c <= 0x10FFFF;
template<typename CharType = unsigned> }
struct UTF32BE : UTF32<CharType> {
template <typename InputByteStream> template <typename InputStream, typename OutputStream>
static CharType TakeBOM(InputByteStream& is) { static bool Validate(InputStream& is, OutputStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
CharType c = Take(is); Ch c;
return (unsigned)c == 0x0000FEFFu ? Take(is) : c; os.Put(c = is.Take());
} return c <= 0x10FFFF;
}
template <typename InputByteStream> };
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); //! UTF-32 little endian enocoding.
CharType c = (unsigned char)is.Take() << 24; template<typename CharType = unsigned>
c |= (unsigned char)is.Take() << 16; struct UTF32LE : UTF32<CharType> {
c |= (unsigned char)is.Take() << 8; template <typename InputByteStream>
c |= (unsigned char)is.Take(); static CharType TakeBOM(InputByteStream& is) {
return c; RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
} CharType c = Take(is);
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
template <typename OutputByteStream> }
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); template <typename InputByteStream>
os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu); static CharType Take(InputByteStream& is) {
} RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
unsigned c = static_cast<uint8_t>(is.Take());
template <typename OutputByteStream> c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
static void Put(OutputByteStream& os, CharType c) { c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
os.Put((c >> 24) & 0xFFu); return static_cast<CharType>(c);
os.Put((c >> 16) & 0xFFu); }
os.Put((c >> 8) & 0xFFu);
os.Put(c & 0xFFu); 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));
// ASCII os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
//! ASCII encoding. }
/*! http://en.wikipedia.org/wiki/ASCII
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char. template <typename OutputByteStream>
\note implements Encoding concept static void Put(OutputByteStream& os, CharType c) {
*/ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
template<typename CharType = char> os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
struct ASCII { os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
typedef CharType Ch; os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
enum { supportUnicode = 0 }; }
};
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { //! UTF-32 big endian encoding.
RAPIDJSON_ASSERT(codepoint <= 0x7F); template<typename CharType = unsigned>
os.Put(static_cast<Ch>(codepoint & 0xFF)); struct UTF32BE : UTF32<CharType> {
} template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
template <typename InputStream> RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
static bool Decode(InputStream& is, unsigned* codepoint) { CharType c = Take(is);
unsigned char c = static_cast<unsigned char>(is.Take()); return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
*codepoint = c; }
return c <= 0X7F;
} template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
template <typename InputStream, typename OutputStream> RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
static bool Validate(InputStream& is, OutputStream& os) { unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
unsigned char c = is.Take(); c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
os.Put(c); c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
return c <= 0x7F; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
} return static_cast<CharType>(c);
}
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { template <typename OutputByteStream>
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); static void PutBOM(OutputByteStream& os) {
Ch c = Take(is); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
return c; os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
} os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
template <typename InputByteStream> os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
static Ch Take(InputByteStream& is) { }
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return is.Take(); template <typename OutputByteStream>
} static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
template <typename OutputByteStream> os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
static void PutBOM(OutputByteStream& os) { os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
(void)os; os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
} }
};
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c) { ///////////////////////////////////////////////////////////////////////////////
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); // ASCII
os.Put(static_cast<typename OutputByteStream::Ch>(c));
} //! 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
// AutoUTF */
template<typename CharType = char>
//! Runtime-specified UTF encoding type of a stream. struct ASCII {
enum UTFType { typedef CharType Ch;
kUTF8 = 0, //!< UTF-8.
kUTF16LE = 1, //!< UTF-16 little endian. enum { supportUnicode = 0 };
kUTF16BE = 2, //!< UTF-16 big endian.
kUTF32LE = 3, //!< UTF-32 little endian. template<typename OutputStream>
kUTF32BE = 4 //!< UTF-32 big endian. static void Encode(OutputStream& os, unsigned codepoint) {
}; RAPIDJSON_ASSERT(codepoint <= 0x7F);
os.Put(static_cast<Ch>(codepoint & 0xFF));
//! 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 OutputStream>
template<typename CharType> static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
struct AutoUTF { RAPIDJSON_ASSERT(codepoint <= 0x7F);
typedef CharType Ch; PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
}
enum { supportUnicode = 1 };
template <typename InputStream>
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x static bool Decode(InputStream& is, unsigned* codepoint) {
uint8_t c = static_cast<uint8_t>(is.Take());
template<typename OutputStream> *codepoint = c;
RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { return c <= 0X7F;
typedef void (*EncodeFunc)(OutputStream&, unsigned); }
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
(*f[os.GetType()])(os, codepoint); template <typename InputStream, typename OutputStream>
} static bool Validate(InputStream& is, OutputStream& os) {
uint8_t c = static_cast<uint8_t>(is.Take());
template <typename InputStream> os.Put(static_cast<typename OutputStream::Ch>(c));
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { return c <= 0x7F;
typedef bool (*DecodeFunc)(InputStream&, unsigned*); }
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
return (*f[is.GetType()])(is, codepoint); template <typename InputByteStream>
} static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
template <typename InputStream, typename OutputStream> uint8_t c = static_cast<uint8_t>(Take(is));
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { return static_cast<Ch>(c);
typedef bool (*ValidateFunc)(InputStream&, OutputStream&); }
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
return (*f[is.GetType()])(is, os); template <typename InputByteStream>
} static Ch Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
#undef RAPIDJSON_ENCODINGS_FUNC return static_cast<Ch>(is.Take());
}; }
/////////////////////////////////////////////////////////////////////////////// template <typename OutputByteStream>
// Transcoder static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
//! Encoding conversion. (void)os;
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 OutputByteStream>
template<typename InputStream, typename OutputStream> static void Put(OutputByteStream& os, Ch c) {
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
unsigned codepoint; os.Put(static_cast<typename OutputByteStream::Ch>(c));
if (!SourceEncoding::Decode(is, &codepoint)) }
return false; };
TargetEncoding::Encode(os, codepoint);
return true; ///////////////////////////////////////////////////////////////////////////////
} // AutoUTF
//! Validate one Unicode codepoint from an encoded stream. //! Runtime-specified UTF encoding type of a stream.
template<typename InputStream, typename OutputStream> enum UTFType {
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { kUTF8 = 0, //!< UTF-8.
return Transcode(is, os); // Since source/target encoding is different, must transcode. kUTF16LE = 1, //!< UTF-16 little endian.
} kUTF16BE = 2, //!< UTF-16 big endian.
}; kUTF32LE = 3, //!< UTF-32 little endian.
kUTF32BE = 4 //!< UTF-32 big endian.
//! Specialization of Transcoder with same source and target encoding. };
template<typename Encoding>
struct Transcoder<Encoding, Encoding> { //! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
template<typename InputStream, typename OutputStream> /*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { */
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. template<typename CharType>
return true; struct AutoUTF {
} typedef CharType Ch;
template<typename InputStream, typename OutputStream> enum { supportUnicode = 1 };
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
return Encoding::Validate(is, os); // source/target encoding are the same #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) {
RAPIDJSON_NAMESPACE_END typedef void (*EncodeFunc)(OutputStream&, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
#if defined(__GNUC__) || defined(_MSV_VER) (*f[os.GetType()])(os, codepoint);
RAPIDJSON_DIAG_POP }
#endif
template<typename OutputStream>
#endif // RAPIDJSON_ENCODINGS_H_ 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_