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 4386 additions and 0 deletions
/**
* `b64.h' - b64
*
* copyright (c) 2014 joseph werle
*/
/*
From https://github.com/littlstar/b64.c/blob/master/LICENSE :
The MIT License (MIT)
Copyright (c) 2014 Little Star Media, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef B64_H
#define B64_H 1
// RYT start
#include <string>
std::string base64_encode(const std::string& bin);
std::string base64_decode(const std::string& b64);
// RYT end
/**
* Memory allocation functions to use. You can define b64_malloc and
* b64_realloc to custom functions if you want.
*/
#ifndef b64_malloc
# define b64_malloc(ptr) malloc(ptr)
#endif
#ifndef b64_realloc
# define b64_realloc(ptr, size) realloc(ptr, size)
#endif
/**
* Base64 index table.
*/
static const char b64_table[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
};
#ifdef __cplusplus
extern "C" {
#endif
/**
* Encode `unsigned char *' source with `size_t' size.
* Returns a `char *' base64 encoded string.
*/
char *
b64_encode (const unsigned char *, size_t);
/**
* Dencode `char *' source with `size_t' size.
* Returns a `unsigned char *' base64 decoded string.
*/
unsigned char *
b64_decode (const char *, size_t);
/**
* Dencode `char *' source with `size_t' size.
* Returns a `unsigned char *' base64 decoded string + size of decoded string.
*/
unsigned char *
b64_decode_ex (const char *, size_t, size_t *);
#ifdef __cplusplus
}
#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-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 January, 2019
*/
#ifndef __ipaaca_backend_mqtt_h_INCLUDED__
#define __ipaaca_backend_mqtt_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
}
// Backend-specific include[s]
#include <mosquittopp.h>
namespace ipaaca {
#define _MQTT_REMOTE_SERVER_MAX_QUEUED_REQUESTS 0
namespace backend {
namespace mqtt {
//
// START of backend-specific implementation
//
// here: MQTT
// helper to encapsulate a wait-until-live mechanism
// you can take this for other backends and adopt the friend class name
class ParticipantCore {
friend class MQTTBackEnd;
protected:
IPAACA_MEMBER_VAR_EXPORT std::condition_variable _condvar;
IPAACA_MEMBER_VAR_EXPORT std::mutex _condvar_mutex;
IPAACA_MEMBER_VAR_EXPORT bool _running;
IPAACA_MEMBER_VAR_EXPORT bool _live;
protected:
IPAACA_HEADER_EXPORT ParticipantCore();
IPAACA_HEADER_EXPORT void signal_live();
IPAACA_HEADER_EXPORT bool wait_live(long timeout_milliseconds = 15000);
};
class MQTTParticipant: public ParticipantCore, public mosqpp::mosquittopp {
public:
typedef std::shared_ptr<MQTTParticipant> ptr;
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _scope;
IPAACA_MEMBER_VAR_EXPORT std::string _client_id;
IPAACA_MEMBER_VAR_EXPORT std::string host;
IPAACA_MEMBER_VAR_EXPORT int port;
IPAACA_MEMBER_VAR_EXPORT int keepalive;
public:
IPAACA_HEADER_EXPORT MQTTParticipant(const MQTTParticipant& orig) = delete; // forbid copy-construction for backend
IPAACA_HEADER_EXPORT inline virtual ~MQTTParticipant() { }
IPAACA_HEADER_EXPORT MQTTParticipant(const std::string& client_id, const std::string& scope, Config::ptr config = nullptr);
IPAACA_HEADER_EXPORT void connect_and_background();
IPAACA_HEADER_EXPORT virtual void on_error();
IPAACA_HEADER_EXPORT virtual void on_disconnect(int rc);
IPAACA_HEADER_EXPORT static int get_next_mid();
/* // available mosquittopp callbacks:
virtual void on_connect(int rc) {return;}
virtual void on_disconnect(int rc) {return;}
virtual void on_publish(int mid) {return;}
virtual void on_message(const struct mosquitto_message * message) {return;}
virtual void on_subscribe(int mid, int qos_count, const int * granted_qos) {return;}
virtual void on_unsubscribe(int mid) {return;}
virtual void on_log(int level, const char * str) {return;}
virtual void on_error() {return;}
*/
};
class MQTTInformer: public MQTTParticipant, public Informer {
public:
typedef std::shared_ptr<MQTTInformer> ptr;
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _client_id;
public:
IPAACA_HEADER_EXPORT MQTTInformer(const std::string& client_id, const std::string& scope, Config::ptr config = nullptr);
IPAACA_HEADER_EXPORT virtual void on_connect(int rc);
IPAACA_HEADER_EXPORT virtual bool internal_publish(const std::string& wire);
};
class MQTTListener: public MQTTParticipant, public Listener {
public:
typedef std::shared_ptr<MQTTListener> ptr;
public:
IPAACA_HEADER_EXPORT MQTTListener(const std::string& client_id, const std::string& scope, InputBuffer* buffer_ptr, Config::ptr config = nullptr);
IPAACA_HEADER_EXPORT virtual void on_connect(int rc);
IPAACA_HEADER_EXPORT virtual void on_subscribe(int mid, int qos_count, const int * granted_qos);
IPAACA_HEADER_EXPORT virtual void on_message(const struct mosquitto_message * message);
};
class MQTTLocalServer: public MQTTParticipant, public LocalServer {
public:
typedef std::shared_ptr<MQTTLocalServer> ptr;
protected:
IPAACA_HEADER_EXPORT void send_result_for_request(const std::string& request_endpoint, const std::string& request_uid, int64_t result);
public:
IPAACA_HEADER_EXPORT MQTTLocalServer(const std::string& client_id, const std::string& scope, ipaaca::OutputBuffer* buffer_ptr, Config::ptr config = nullptr);
IPAACA_HEADER_EXPORT virtual void on_connect(int rc);
IPAACA_HEADER_EXPORT virtual void on_subscribe(int mid, int qos_count, const int * granted_qos);
IPAACA_HEADER_EXPORT virtual void on_message(const struct mosquitto_message * message);
};
class MQTTRemoteServer: public MQTTParticipant, public RemoteServer {
public:
typedef std::shared_ptr<RemoteServer> ptr;
protected:
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, PendingRequest::ptr> _pending_requests;
IPAACA_MEMBER_VAR_EXPORT ipaaca::Lock _pending_requests_lock;
IPAACA_MEMBER_VAR_EXPORT std::string _remote_end_scope; // this is the actual important scope,
// MQTTParticipant::_scope is repurposed here for receiving replies
IPAACA_MEMBER_VAR_EXPORT std::string _name; // using this (unique) auto-generated name
public:
IPAACA_HEADER_EXPORT MQTTRemoteServer(const std::string& client_id, const std::string& scope, Config::ptr config = nullptr);
IPAACA_HEADER_EXPORT int64_t request_remote_payload_update(std::shared_ptr<IUPayloadUpdate> update);
IPAACA_HEADER_EXPORT int64_t request_remote_link_update(std::shared_ptr<IULinkUpdate> update);
IPAACA_HEADER_EXPORT int64_t request_remote_commission(std::shared_ptr<protobuf::IUCommission> update);
IPAACA_HEADER_EXPORT int64_t request_remote_resend_request(std::shared_ptr<protobuf::IUResendRequest> update);
IPAACA_HEADER_EXPORT virtual void on_connect(int rc);
IPAACA_HEADER_EXPORT virtual void on_subscribe(int mid, int qos_count, const int * granted_qos);
IPAACA_HEADER_EXPORT virtual void on_message(const struct mosquitto_message * message);
IPAACA_HEADER_EXPORT PendingRequest::ptr queue_pending_request(Event::ptr request);
IPAACA_HEADER_EXPORT int64_t blocking_call(Event::ptr request);
};
class MQTTBackEnd: public BackEnd
{
public:
typedef std::shared_ptr<MQTTBackEnd> ptr;
friend class BackEndLibrary;
protected:
IPAACA_HEADER_EXPORT MQTTBackEnd();
public:
IPAACA_HEADER_EXPORT static BackEnd::ptr get();
IPAACA_HEADER_EXPORT void teardown();
IPAACA_HEADER_EXPORT Informer::ptr createInformer(const std::string& scope);
IPAACA_HEADER_EXPORT Listener::ptr createListener(const std::string& scope, InputBuffer* buf);
IPAACA_HEADER_EXPORT LocalServer::ptr createLocalServer(const std::string& scope, OutputBuffer* buf);
IPAACA_HEADER_EXPORT RemoteServer::ptr createRemoteServer(const std::string& scope);
IPAACA_HEADER_EXPORT inline std::string make_valid_scope(const std::string& scope) override { return scope; }
};
} // of namespace mqtt
} // of namespace backend
#endif // of __ipaaca_backend_mqtt_h_INCLUDED__
/*
* 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 January, 2019
*/
#ifndef __ipaaca_backend_ros_h_INCLUDED__
#define __ipaaca_backend_ros_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
}
// Backend-specific include[s]
#include "ros/ros.h"
#include "std_msgs/String.h"
namespace ipaaca {
#define _ROS_REMOTE_SERVER_MAX_QUEUED_REQUESTS 0
namespace backend {
namespace ros {
//
// START of backend-specific implementation
//
// here: ROS
// helper to encapsulate a wait-until-live mechanism
// you can take this for other backends and adopt the friend class name
class ParticipantCore {
friend class ROSBackEnd;
protected:
IPAACA_MEMBER_VAR_EXPORT std::condition_variable _condvar;
IPAACA_MEMBER_VAR_EXPORT std::mutex _condvar_mutex;
IPAACA_MEMBER_VAR_EXPORT bool _running;
IPAACA_MEMBER_VAR_EXPORT bool _live;
protected:
IPAACA_HEADER_EXPORT ParticipantCore();
IPAACA_HEADER_EXPORT void signal_live();
IPAACA_HEADER_EXPORT bool wait_live(long timeout_milliseconds = 15000);
};
class ROSParticipant: public ParticipantCore {
public:
typedef std::shared_ptr<ROSParticipant> ptr;
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _scope;
IPAACA_MEMBER_VAR_EXPORT std::string host;
IPAACA_MEMBER_VAR_EXPORT int port;
IPAACA_MEMBER_VAR_EXPORT int keepalive;
protected:
// a pointer; odd, but see the ROSBackEnd constructor & destructor
::ros::NodeHandle* _node_handle;
public:
IPAACA_HEADER_EXPORT ROSParticipant(const ROSParticipant& orig) = delete; // forbid copy-construction for backend
IPAACA_HEADER_EXPORT inline virtual ~ROSParticipant() { }
IPAACA_HEADER_EXPORT ROSParticipant(::ros::NodeHandle* node, const std::string& scope, Config::ptr config = nullptr);
};
class ROSInformer: public ROSParticipant, public Informer {
public:
typedef std::shared_ptr<ROSInformer> ptr;
protected:
::ros::Publisher _ros_pub;
public:
IPAACA_HEADER_EXPORT ROSInformer(::ros::NodeHandle* node, const std::string& scope, Config::ptr config = nullptr);
IPAACA_HEADER_EXPORT virtual bool internal_publish(const std::string& wire);
};
class ROSListener: public ROSParticipant, public Listener {
public:
typedef std::shared_ptr<ROSListener> ptr;
protected:
IPAACA_MEMBER_VAR_EXPORT ::ros::Subscriber _ros_sub;
public:
IPAACA_HEADER_EXPORT ROSListener(::ros::NodeHandle* node, const std::string& scope, InputBuffer* buffer_ptr, Config::ptr config = nullptr);
IPAACA_HEADER_EXPORT virtual void on_message(const std_msgs::String::ConstPtr& msg);
};
class ROSLocalServer: public ROSParticipant, public LocalServer {
public:
typedef std::shared_ptr<ROSLocalServer> ptr;
protected:
IPAACA_MEMBER_VAR_EXPORT ::ros::Subscriber _ros_sub;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, ::ros::Publisher> _ros_pubs;
protected:
IPAACA_HEADER_EXPORT void send_result_for_request(const std::string& request_endpoint, const std::string& request_uid, int64_t result);
IPAACA_HEADER_EXPORT ::ros::Publisher get_publisher(const std::string& endpoint);
public:
IPAACA_HEADER_EXPORT ROSLocalServer(::ros::NodeHandle* node, const std::string& scope, ipaaca::OutputBuffer* buffer_ptr, Config::ptr config = nullptr);
IPAACA_HEADER_EXPORT virtual void on_message(const std_msgs::String::ConstPtr& msg);
};
class ROSRemoteServer: public ROSParticipant, public RemoteServer {
public:
typedef std::shared_ptr<RemoteServer> ptr;
protected:
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, PendingRequest::ptr> _pending_requests;
IPAACA_MEMBER_VAR_EXPORT ipaaca::Lock _pending_requests_lock;
IPAACA_MEMBER_VAR_EXPORT std::string _remote_end_scope; // this is the actual important scope,
// ROSParticipant::_scope is repurposed here for receiving replies
IPAACA_MEMBER_VAR_EXPORT std::string _name; // using this (unique) auto-generated name
IPAACA_MEMBER_VAR_EXPORT ::ros::Subscriber _ros_sub;
IPAACA_MEMBER_VAR_EXPORT ::ros::Publisher _ros_pub;
public:
IPAACA_HEADER_EXPORT ROSRemoteServer(::ros::NodeHandle* node, const std::string& scope, Config::ptr config = nullptr);
IPAACA_HEADER_EXPORT int64_t request_remote_payload_update(std::shared_ptr<IUPayloadUpdate> update);
IPAACA_HEADER_EXPORT int64_t request_remote_link_update(std::shared_ptr<IULinkUpdate> update);
IPAACA_HEADER_EXPORT int64_t request_remote_commission(std::shared_ptr<protobuf::IUCommission> update);
IPAACA_HEADER_EXPORT int64_t request_remote_resend_request(std::shared_ptr<protobuf::IUResendRequest> update);
IPAACA_HEADER_EXPORT PendingRequest::ptr queue_pending_request(Event::ptr request);
IPAACA_HEADER_EXPORT int64_t blocking_call(Event::ptr request);
IPAACA_HEADER_EXPORT virtual void on_message(const std_msgs::String::ConstPtr& msg);
};
class ROSBackEnd: public BackEnd
{
public:
typedef std::shared_ptr<ROSBackEnd> ptr;
friend class BackEndLibrary;
protected:
bool _need_init;
char* _cfakename;
::ros::NodeHandle* _node_handle;
::ros::AsyncSpinner* _spinner;
protected:
IPAACA_HEADER_EXPORT ROSBackEnd();
public:
IPAACA_HEADER_EXPORT static BackEnd::ptr get();
IPAACA_HEADER_EXPORT void teardown();
IPAACA_HEADER_EXPORT void init_once();
IPAACA_HEADER_EXPORT Informer::ptr createInformer(const std::string& scope);
IPAACA_HEADER_EXPORT Listener::ptr createListener(const std::string& scope, InputBuffer* buf);
IPAACA_HEADER_EXPORT LocalServer::ptr createLocalServer(const std::string& scope, OutputBuffer* buf);
IPAACA_HEADER_EXPORT RemoteServer::ptr createRemoteServer(const std::string& scope);
IPAACA_HEADER_EXPORT inline std::string make_valid_scope(const std::string& scope) override {
// strip the leading slash for the ROS node name (removing this
// extra rule would lead to a global (non-movable) namespace
if (scope.length() && (scope[0] == '/')) return scope.substr(1);
else return scope;
}
};
} // of namespace ros
} // of namespace backend
#endif // of __ipaaca_backend_ros_h_INCLUDED__
/*
* 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
/*
* 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.
*/
#ifndef __ipaaca_buffers_h_INCLUDED__
#define __ipaaca_buffers_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#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)
class IUStore: public std::map<std::string, std::shared_ptr<IU> >
{
};
/// Store for RemotePushIUs (used in InputBuffer)
class RemotePushIUStore: public std::map<std::string, std::shared_ptr<RemotePushIU> >
{
};
typedef std::set<std::string> LinkSet;
typedef std::map<std::string, LinkSet> LinkMap;
/// Container for IU links that gracefully returns the empty set if required
class SmartLinkMap {//{{{
friend std::ostream& operator<<(std::ostream& os, const SmartLinkMap& obj);
friend class IUInterface;
friend class IU;
friend class ipaaca::converters::IUConverter;
//friend class ipaaca::converters::MessageConverter;
public:
IPAACA_HEADER_EXPORT const LinkSet& get_links(const std::string& key);
IPAACA_HEADER_EXPORT const LinkMap& get_all_links();
protected:
IPAACA_MEMBER_VAR_EXPORT LinkMap _links;
/// The empty link set is returned if undefined links are read for an IU.
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 _replace_links(const LinkMap& links);
};//}}}
/// The empty link set is returned if undefined links are read for an IU.
IPAACA_MEMBER_VAR_EXPORT const LinkSet EMPTY_LINK_SET;
/// Configuration object that can be passed to Buffer constructors.
class BufferConfiguration//{{{
{
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _basename;
IPAACA_MEMBER_VAR_EXPORT std::vector<std::string> _category_interests;
IPAACA_MEMBER_VAR_EXPORT std::string _channel;
public:
IPAACA_HEADER_EXPORT inline BufferConfiguration(const std::string& basename): _basename(basename), _channel(__ipaaca_static_option_default_channel) { }
IPAACA_HEADER_EXPORT inline const std::string& get_basename() const { return _basename; }
IPAACA_HEADER_EXPORT inline const std::vector<std::string>& get_category_interests() const { return _category_interests; }
IPAACA_HEADER_EXPORT inline const std::string& get_channel() const { return _channel; }
public:
// setters, initialization helpers
IPAACA_HEADER_EXPORT inline BufferConfiguration& set_basename(const std::string& basename) { _basename = basename; return *this; }
IPAACA_HEADER_EXPORT inline BufferConfiguration& add_category_interest(const std::string& category) { _category_interests.push_back(category); return *this; }
IPAACA_HEADER_EXPORT inline BufferConfiguration& set_channel(const std::string& channel) { _channel = channel; return *this; }
};//}}}
/// Builder object for BufferConfiguration, not required for C++ [DEPRECATED]
class BufferConfigurationBuilder: private BufferConfiguration//{{{
{
public:
[[deprecated("Use setters in BufferConfiguration instead of the Builder")]]
IPAACA_HEADER_EXPORT inline BufferConfigurationBuilder(const std::string& basename): BufferConfiguration(basename) {}
IPAACA_HEADER_EXPORT inline void set_basename(const std::string& basename)
{
_basename = basename;
}
IPAACA_HEADER_EXPORT inline void add_category_interest(const std::string& category)
{
_category_interests.push_back(category);
}
IPAACA_HEADER_EXPORT inline void set_channel(const std::string& channel)
{
_channel = channel;
}
IPAACA_HEADER_EXPORT const BufferConfiguration& get_buffer_configuration() { return *this; }
};//}}}
/** \brief Type of user-space functions that can be registered on a Buffer to receive IU events.
*
* The signature of these functions is void(shared_ptr<IUInterface> iu, IUEventType evt_type, bool local), where:<br/>
* iu can be used mostly like a locally-generated IU reference (e.g. iu->payload() ...)<br/>
* evt_type is one of IU_ADDED, IU_UPDATED, IU_RETRACTED, IU_DELETED, IU_LINKSUPDATED, IU_COMMITTED, IU_MESSAGE<br/>
* local indicates that a remote change to a local IU (in an OutputBuffer) was effected
*
* See #Buffer::register_handler for examples on how to use your own handlers.
*/
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)
*/
class IUEventHandler {//{{{
protected:
IPAACA_MEMBER_VAR_EXPORT IUEventHandlerFunction _function;
IPAACA_MEMBER_VAR_EXPORT IUEventType _event_mask;
IPAACA_MEMBER_VAR_EXPORT bool _for_all_categories;
IPAACA_MEMBER_VAR_EXPORT std::set<std::string> _categories;
protected:
IPAACA_HEADER_EXPORT inline bool _condition_met(IUEventType event_type, const std::string& category)
{
return ((_event_mask&event_type)!=0) && (_for_all_categories || (_categories.count(category)>0));
}
public:
IPAACA_HEADER_EXPORT IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::string& category);
IPAACA_HEADER_EXPORT IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories);
IPAACA_HEADER_EXPORT void call(Buffer* buffer, std::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category);
typedef std::shared_ptr<IUEventHandler> ptr;
};//}}}
/**
* \brief Buffer base class. Derived classes use its handler registration functionality.
*
* \b Note: This class is never instantiated directly (use OutputBuffer and InputBuffer, respectively).
*/
class Buffer {
friend class IU;
friend class RemotePushIU;
/*friend class CallbackIUPayloadUpdate;
friend class CallbackIULinkUpdate;
friend class CallbackIUCommission;
friend class CallbackIUResendRequest;*/
friend class ipaaca::backend::LocalServer;
friend class ipaaca::backend::Listener;
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _uuid;
IPAACA_MEMBER_VAR_EXPORT std::string _basename;
IPAACA_MEMBER_VAR_EXPORT std::string _unique_name;
IPAACA_MEMBER_VAR_EXPORT std::string _id_prefix;
IPAACA_MEMBER_VAR_EXPORT std::string _channel;
IPAACA_MEMBER_VAR_EXPORT std::vector<IUEventHandler::ptr> _event_handlers;
protected:
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_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 void _allocate_unique_name(const std::string& basename, const std::string& function);
IPAACA_HEADER_EXPORT inline Buffer(const std::string& basename, const std::string& function) {
_allocate_unique_name(basename, function);
_channel = __ipaaca_static_option_default_channel;
}
IPAACA_HEADER_EXPORT void call_iu_event_handlers(std::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category);
public:
IPAACA_HEADER_EXPORT virtual inline ~Buffer() { }
IPAACA_HEADER_EXPORT inline const std::string& unique_name() { return _unique_name; }
/** \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 event_mask Which event types to relay to the user (default: all)
* \param category The category to filter for (default: do not filter)
*
* \b Examples:
*
* Adding a plain function as a handler:<br/>
* <pre>
* void global_iu_handler(IUInterface::ptr iu, IUEventType type, bool local) { do_something(); }
* ...
* int main() {
* OutputBuffer::ptr outbuf = OutputBuffer::create("mybufname");
* outbuf->register_handler(global_iu_handler);
* ...
* }
* </pre>
*
* Adding a class member as a handler (using macro or std::bind):<br/>
* <pre>
* class MyClass {
* protected:
* void my_internal_iu_handler(IUInterface::ptr iu, #IUEventType type, bool local) { do_something(); }
* InputBuffer::ptr inbuf;
* public:
* MyClass() {
* inbuf = InputBuffer::create("bufname", "categoryInterest");
* // 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>
*
* Adding a lambda function as a handler (C++11):<br/>
* <pre>
* inbuf->register_handler([](IUInterface::ptr iu, #IUEventType event_type, bool local) {
* do_something();
* });
* </pre>
*
*/
IPAACA_HEADER_EXPORT void register_handler(IUEventHandlerFunction function, IUEventType event_mask = IU_ALL_EVENTS, const std::string& category="");
/// 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);
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; }
};
//}}}
/**
* \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::add to add (= publish) 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.
*/
class OutputBuffer: public Buffer {
friend class IU;
friend class RemotePushIU;
friend class ipaaca::backend::LocalServer;
protected:
protected:
IPAACA_MEMBER_VAR_EXPORT IUStore _iu_store;
IPAACA_MEMBER_VAR_EXPORT Lock _iu_id_counter_lock;
#ifdef IPAACA_EXPOSE_FULL_RSB_API
protected:
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, ipaaca::backend::Informer::ptr> _informer_store;
IPAACA_MEMBER_VAR_EXPORT ipaaca::backend::LocalServer::ptr _server;
IPAACA_HEADER_EXPORT ipaaca::backend::Informer::ptr _get_informer(const std::string& category);
#endif
protected:
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(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_commission(IUInterface* iu, revision_t revision, const std::string& writer_name) _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void _publish_iu(std::shared_ptr<IU> iu);
/// mark and send IU retraction on own IU (removal from buffer is in remove(IU))
IPAACA_HEADER_EXPORT void _retract_iu(std::shared_ptr<IU> iu);
/// mark and send retraction for all unretracted IUs (without removal, used in ~OutputBuffer)
IPAACA_HEADER_EXPORT void _retract_all_internal();
protected:
/// \b Note: constructor is protected. Use create()
IPAACA_HEADER_EXPORT OutputBuffer(const std::string& basename, const std::string& channel=""); // empty string auto-replaced with __ipaaca_static_option_default_channel
IPAACA_HEADER_EXPORT void _initialize_server();
public:
IPAACA_HEADER_EXPORT static std::shared_ptr<OutputBuffer> create(const std::string& basename);
/// OutputBuffer destructor will retract all IUs that are still live
IPAACA_HEADER_EXPORT ~OutputBuffer();
IPAACA_HEADER_EXPORT void add(std::shared_ptr<IU> iu);
IPAACA_HEADER_EXPORT std::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 std::shared_ptr<IUInterface> get(const std::string& iu_uid) _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT std::set<std::shared_ptr<IUInterface> > get_ius() _IPAACA_OVERRIDE_;
typedef std::shared_ptr<OutputBuffer> ptr;
};
//}}}
/**
* \brief A buffer in which remote IUs (and changes to them) are received.
*
* Use InputBuffer::create() to obtain a smart pointer to a new input buffer.
*
* Set category interests (IU filter) via the different versions of create().
*
* Use Buffer::register_handler() to register a handler that will respond to relevant remote IUs.
*/
class InputBuffer: public Buffer {
friend class IU;
friend class RemotePushIU;
friend class ipaaca::backend::Listener;
#ifdef IPAACA_EXPOSE_FULL_RSB_API
protected:
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, ipaaca::backend::Listener::ptr> _listener_store;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, ipaaca::backend::RemoteServer::ptr> _remote_server_store;
IPAACA_MEMBER_VAR_EXPORT RemotePushIUStore _iu_store;
IPAACA_HEADER_EXPORT ipaaca::backend::RemoteServer::ptr _get_remote_server(const std::string& unique_server_name);
IPAACA_HEADER_EXPORT ipaaca::backend::Listener::ptr _create_category_listener_if_needed(const std::string& category);
IPAACA_HEADER_EXPORT void _handle_iu_events(ipaaca::backend::Event::ptr event);
IPAACA_HEADER_EXPORT void _trigger_resend_request(ipaaca::backend::Event::ptr event);
#endif
protected:
IPAACA_HEADER_EXPORT inline void _send_iu_link_update(IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name="undef") _IPAACA_OVERRIDE_
{
IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_link_update() should never be invoked")
}
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_HEADER_EXPORT inline 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_WARNING("(ERROR) InputBuffer::_send_iu_payload_update() should never be invoked")
}
IPAACA_HEADER_EXPORT inline void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name="undef") _IPAACA_OVERRIDE_
{
IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_commission() should never be invoked")
}
/*IPAACA_HEADER_EXPORT inline void _send_iu_resendrequest(IUInterface* iu, revision_t revision, const std::string& writer_name="undef")
{
IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_resendrequest() should never be invoked")
}*/
protected:
/// \b Note: all constructors are protected. Use create()
IPAACA_HEADER_EXPORT InputBuffer(const BufferConfiguration& bufferconfiguration);
IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::set<std::string>& category_interests);
IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::vector<std::string>& category_interests);
IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::string& category_interest1);
IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2);
IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3);
IPAACA_HEADER_EXPORT InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3, const std::string& category_interest4);
IPAACA_MEMBER_VAR_EXPORT bool triggerResend;
public:
/// Specify whether old but previously unseen IUs should be requested to be sent to the buffer over a hidden channel.
IPAACA_HEADER_EXPORT void set_resend(bool resendActive);
IPAACA_HEADER_EXPORT bool get_resend();
/// Create InputBuffer according to configuration in BufferConfiguration object
IPAACA_HEADER_EXPORT static std::shared_ptr<InputBuffer> create(const BufferConfiguration& bufferconfiguration);
/// Create InputBuffer from name and set of 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
IPAACA_HEADER_EXPORT static std::shared_ptr<InputBuffer> create(const std::string& basename, const std::vector<std::string>& category_interests);
/// Convenience function: create InputBuffer from name and one category interest
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]
[[deprecated("Use create(string, set<string>) instead")]]
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]
[[deprecated("Use create(string, set<string>) instead")]]
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]
[[deprecated("Use create(string, set<string>) instead")]]
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_IMPLEMENT_ME
}
IPAACA_HEADER_EXPORT std::shared_ptr<IUInterface> get(const std::string& iu_uid) _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT std::set<std::shared_ptr<IUInterface> > get_ius() _IPAACA_OVERRIDE_;
typedef std::shared_ptr<InputBuffer> ptr;
};
//}}}
/// Internal, transport-independent, representation of payload updates
class IUPayloadUpdate {//{{{
public:
IPAACA_MEMBER_VAR_EXPORT std::string uid;
IPAACA_MEMBER_VAR_EXPORT revision_t revision;
IPAACA_MEMBER_VAR_EXPORT std::string writer_name;
IPAACA_MEMBER_VAR_EXPORT bool is_delta;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, PayloadDocumentEntry::ptr> new_items;
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 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);
typedef std::shared_ptr<IUPayloadUpdate> ptr;
};//}}}
/// Internal, transport-independent, representation of link updates
class IULinkUpdate {//{{{
public:
IPAACA_MEMBER_VAR_EXPORT std::string uid;
IPAACA_MEMBER_VAR_EXPORT revision_t revision;
IPAACA_MEMBER_VAR_EXPORT std::string writer_name;
IPAACA_MEMBER_VAR_EXPORT bool is_delta;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, std::set<std::string> > new_links;
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, std::set<std::string> > links_to_remove;
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);
typedef std::shared_ptr<IULinkUpdate> 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-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
/*
* 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-internal.h
*
* \brief Header file for internal transport implementation (RSB).
*
* 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.
*
* The file provides callback glue from RSB, and wire converters
* for the respective ipaaca classes.
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_converters_h_INCLUDED__
#define __ipaaca_converters_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
namespace converters {
// 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);
// 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);
// deserialization (just switching here instead of the converter registry business)
std::shared_ptr<ipaaca::backend::Event> internal_deserialize(const std::string& wire);
class IUConverter {//{{{
public:
IPAACA_HEADER_EXPORT static std::string serialize(std::shared_ptr<ipaaca::IU> iu); // const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT static std::shared_ptr<ipaaca::IUInterface> deserialize(const std::string& wire);
};//}}}
/*
IPAACA_HEADER_EXPORT class MessageConverter {//{{{
public:
IPAACA_HEADER_EXPORT static std::string serialize(std::shared_ptr<ipaaca::Message> msg); // const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT static std::shared_ptr<ipaaca::RemoteMessage> deserialize(const std::string& wire);
};//}}}
*/
class IUPayloadUpdateConverter {//{{{
public:
IPAACA_HEADER_EXPORT static std::string serialize(std::shared_ptr<ipaaca::IUPayloadUpdate> pup); // const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT static std::shared_ptr<ipaaca::IUPayloadUpdate> deserialize(const std::string& wire);
};//}}}
class IULinkUpdateConverter {//{{{
public:
IPAACA_HEADER_EXPORT static std::string serialize(std::shared_ptr<ipaaca::IULinkUpdate> lup); // const rsb::AnnotatedData& data, std::string& wire);
IPAACA_HEADER_EXPORT static std::shared_ptr<ipaaca::IULinkUpdate> deserialize(const std::string& wire);
};//}}}
} // of namespace converters
#endif // __ipaaca_converters_h_INCLUDED__
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-definitions.h
*
* \brief Header file for data and exception types and helper functions.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_definitions_h_INCLUDED__
#define __ipaaca_definitions_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
typedef uint32_t revision_t;
/// Type of the IU event. Realized as an integer to enable bit masks for filters. One of: IU_ADDED, IU_COMMITTED, IU_DELETED, IU_RETRACTED, IU_UPDATED, IU_LINKSUPDATED, IU_MESSAGE
typedef uint32_t IUEventType;
#define IU_ADDED 1
#define IU_COMMITTED 2
#define IU_DELETED 4
#define IU_RETRACTED 8
#define IU_UPDATED 16
#define IU_LINKSUPDATED 32
#define IU_MESSAGE 64
/// Bit mask for receiving all IU events \see IUEventType
#define IU_ALL_EVENTS 127
/// Ipaaca (console) log levels
#define IPAACA_LOG_LEVEL_NONE 0
#define IPAACA_LOG_LEVEL_CRITICAL 1
#define IPAACA_LOG_LEVEL_ERROR 2
#define IPAACA_LOG_LEVEL_WARNING 3
#define IPAACA_LOG_LEVEL_INFO 4
#define IPAACA_LOG_LEVEL_DEBUG 5
/// Convert an int event type to a human-readable string
IPAACA_HEADER_EXPORT inline std::string iu_event_type_to_str(IUEventType type)
{
switch(type) {
case IU_ADDED: return "ADDED";
case IU_COMMITTED: return "COMMITTED";
case IU_DELETED: return "DELETED";
case IU_RETRACTED: return "RETRACTED";
case IU_UPDATED: return "UPDATED";
case IU_LINKSUPDATED: return "LINKSUPDATED";
case IU_MESSAGE: return "MESSAGE";
default: return "(NOT A KNOWN SINGLE IU EVENT TYPE)";
}
}
/// IU access mode: PUSH means that updates are broadcast; REMOTE means that reads are RPC calls (currently NOT implemented); MESSAGE means a fire-and-forget message
enum IUAccessMode {
IU_ACCESS_PUSH,
IU_ACCESS_REMOTE,
IU_ACCESS_MESSAGE
};
/// generate a UUID as an ASCII string
IPAACA_HEADER_EXPORT std::string generate_uuid_string();
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-errors.h
*
* \brief Header file for all errors and exceptions
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date February, 2019
*/
#ifndef __ipaaca_errors_h_INCLUDED__
#define __ipaaca_errors_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
/**
* Exception with string description
*/
class Exception: public std::exception//{{{
{
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _description;
public:
IPAACA_HEADER_EXPORT inline Exception(const std::string& description=""): _description(description) { }
IPAACA_HEADER_EXPORT inline ~Exception() throw() { }
IPAACA_HEADER_EXPORT const char* what() const throw() {
return _description.c_str();
}
};//}}}
class Abort: public std::exception//{{{
{
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _description;
public:
IPAACA_HEADER_EXPORT inline Abort(const std::string& description=""): _description(description) { }
IPAACA_HEADER_EXPORT inline ~Abort() throw() { }
IPAACA_HEADER_EXPORT const char* what() const throw() {
return _description.c_str();
}
};//}}}
/// BackEnd failed conditions, e.g. limits
class BackEndBadConditionError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~BackEndBadConditionError() throw() { }
IPAACA_HEADER_EXPORT inline BackEndBadConditionError() { //std::shared_ptr<BackEnd> iu) {
_description = "BackEndBadConditionError";
}
};//}}}
/// BackEnd [hard-]failed to connect a participant
class BackEndConnectionFailedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~BackEndConnectionFailedError() throw() { }
IPAACA_HEADER_EXPORT inline BackEndConnectionFailedError() { //std::shared_ptr<BackEnd> iu) {
_description = "BackEndConnectionFailedError";
}
};//}}}
/// BackEnd not found
class BackEndNotFoundError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~BackEndNotFoundError() throw() { }
IPAACA_HEADER_EXPORT inline BackEndNotFoundError() { //std::shared_ptr<BackEnd> iu) {
_description = "BackEndNotFoundError";
}
};//}}}
/// Unknown wire type encountered
class UnhandledWireTypeError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~UnhandledWireTypeError() throw() { }
IPAACA_HEADER_EXPORT inline UnhandledWireTypeError(int wire_type=-1) {
if (wire_type>0) {
_description = "UnhandledWireTypeError (wire type encountered: " + std::to_string(wire_type) + ")";
} else {
_description = "UnhandledWireTypeError (value not provided)";
}
}
};//}}}
/// IU was not found in a buffer
class IUNotFoundError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUNotFoundError() throw() { }
IPAACA_HEADER_EXPORT inline IUNotFoundError() { //std::shared_ptr<IU> iu) {
_description = "IUNotFoundError";
}
};//}}}
/// IU was already published
class IUPublishedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUPublishedError() throw() { }
IPAACA_HEADER_EXPORT inline IUPublishedError() {
_description = "IUPublishedError";
}
};//}}}
/// IU had already been committed to
class IUCommittedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUCommittedError() throw() { }
IPAACA_HEADER_EXPORT inline IUCommittedError() {
_description = "IUCommittedError";
}
};//}}}
/// IU had already been retracted
class IURetractedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IURetractedError() throw() { }
IPAACA_HEADER_EXPORT inline IURetractedError() {
_description = "IURetractedError";
}
};//}}}
/// Remote IU update failed because it had been modified in the mean time
class IUUpdateFailedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUUpdateFailedError() throw() { }
IPAACA_HEADER_EXPORT inline IUUpdateFailedError() {
_description = "IUUpdateFailedError";
}
};//}}}
/// Requested resend of old IU due to malformed channel specification
class IUResendRequestFailedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUResendRequestFailedError() throw() { }
IPAACA_HEADER_EXPORT inline IUResendRequestFailedError() {
_description = "IUResendRequestFailedError";
}
};//}}}
/// Write operation failed because IU had been set read-only
class IUReadOnlyError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUReadOnlyError() throw() { }
IPAACA_HEADER_EXPORT inline IUReadOnlyError() {
_description = "IUReadOnlyError";
}
};//}}}
/// Buffer::add() failed because the IU had been previously placed in another buffer
class IUAlreadyInABufferError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUAlreadyInABufferError() throw() { }
IPAACA_HEADER_EXPORT inline IUAlreadyInABufferError() {
_description = "IUAlreadyInABufferError";
}
};//}}}
/// A request was made that is only valid for an already published IU
class IUUnpublishedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUUnpublishedError() throw() { }
IPAACA_HEADER_EXPORT inline IUUnpublishedError() {
_description = "IUUnpublishedError";
}
};//}}}
/// IU had already been allocated a UID
class IUAlreadyHasAnUIDError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUAlreadyHasAnUIDError() throw() { }
IPAACA_HEADER_EXPORT inline IUAlreadyHasAnUIDError() {
_description = "IUAlreadyHasAnUIDError";
}
};//}}}
/// IU had already been allocated an owner name
class IUAlreadyHasAnOwnerNameError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~IUAlreadyHasAnOwnerNameError() throw() { }
IPAACA_HEADER_EXPORT inline IUAlreadyHasAnOwnerNameError() {
_description = "IUAlreadyHasAnOwnerNameError";
}
};//}}}
/// UID generation failed (Windows only)
class UUIDGenerationError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~UUIDGenerationError() throw() { }
IPAACA_HEADER_EXPORT inline UUIDGenerationError() {
_description = "UUIDGenerationError";
}
};//}}}
/// Not implemented (e.g. invalid request parameters via backend)
class NotImplementedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~NotImplementedError() throw() { }
IPAACA_HEADER_EXPORT inline NotImplementedError() {
_description = "NotImplementedError";
}
};//}}}
/// PayloadEntryProxy requested type conversion failed (including lenient interpretation)
class PayloadTypeConversionError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadTypeConversionError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadTypeConversionError() {
_description = "PayloadTypeConversionError";
}
};//}}}
/// PayloadEntryProxy was addressed as list when not a list or as map when not a map
class PayloadAddressingError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadAddressingError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadAddressingError() {
_description = "PayloadAddressingError";
}
};//}}}
/// Malformed json was received for a Payload
class JsonParsingError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~JsonParsingError() throw() { }
IPAACA_HEADER_EXPORT inline JsonParsingError() {
_description = "JsonParsingError";
}
};//}}}
/// PayloadEntryProxy invalidated (unused)
class PayloadEntryProxyInvalidatedError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadEntryProxyInvalidatedError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadEntryProxyInvalidatedError() {
_description = "PayloadEntryProxyInvalidatedError";
}
};//}}}
/// Iterator over Payload entries was invalidated by an intermediate IU update operation
class PayloadIteratorInvalidError: public Exception//{{{
{
public:
IPAACA_HEADER_EXPORT inline ~PayloadIteratorInvalidError() throw() { }
IPAACA_HEADER_EXPORT inline PayloadIteratorInvalidError() {
_description = "PayloadIteratorInvalidError";
}
};//}}}
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-forwards.h
*
* \brief Header file for forward definitions.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_forwards_h_INCLUDED__
#define __ipaaca_forwards_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
/*
* forward declarations
*/
namespace backend {
//class Scope;
class Event;
class Informer;
class Listener;
class LocalServer;
class RemoteServer;
} // of namespace backend
class PayloadDocumentEntry;
class PayloadBatchUpdateLock;
class PayloadEntryProxy;
class Payload;
class PayloadIterator;
class IUInterface;
class IU;
class Message;
class RemotePushIU;
class RemoteMessage;
class IULinkUpdate;
class IUPayloadUpdate;
class IUStore;
class FrozenIUStore;
class Buffer;
class InputBuffer;
class OutputBuffer;
class CallbackIUPayloadUpdate;
class CallbackIULinkUpdate;
class CallbackIUCommission;
class CallbackIUResendRequest;
class CallbackIURetraction;
class IUConverter;
class MessageConverter;
class IUPayloadUpdateConverter;
class IULinkUpdateConverter;
//class IntConverter;
class BufferConfiguration;
class BufferConfigurationBuilder;
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-initializer.h
*
* \brief Header file for the global initializer unit
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date February, 2019
*/
#ifndef __ipaaca_initializer_h_INCLUDED__
#define __ipaaca_initializer_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
/** \brief Static library initialization for backend
*
* This static class (singleton) is called once (explicitly or on-demand).
* Unless called manually, it is initialized when ipaaca is first used
* (i.e. the first Buffer is created).
*/
class Initializer
{
public:
/// Initialize the backend [DEPRECATED] (old name, use initialize_backend() instead)
[[deprecated("Use initialize_backend() instead")]]
IPAACA_HEADER_EXPORT static void initialize_ipaaca_rsb_if_needed();
/// Explicitly initialize the backend (usually not required). No effect if already initialized. Automatically called during first Buffer construction.
IPAACA_HEADER_EXPORT static void initialize_backend();
IPAACA_HEADER_EXPORT static bool initialized();
IPAACA_HEADER_EXPORT static void dump_current_default_config();
protected:
/** Perform rsb pre-setup before the implicit initialization
* (when first instantiating something). Pre-setup includes
* finding the RSB plugin dir, looking through several parent
* directories for a path "deps/lib/rsb*"/plugins. The path
* can also be set directly (env var RSB_PLUGINS_CPP_PATH),
* which disables the automatic search.
*/
IPAACA_HEADER_EXPORT static void override_env_with_cmdline_set_variables();
IPAACA_MEMBER_VAR_EXPORT static bool _initialized;
};
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-ius.h
*
* \brief Header file for IU (incremental unit) classes.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_ius_h_INCLUDED__
#define __ipaaca_ius_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
/** \brief Abstract base class for all IU-type classes
*
* In user programs, classes IU or Message should be instantiated.
*
* This abstract type is used in handler callback functions and
* contains most generic user-space functions.
*
*/
class IUInterface {//{{{
friend class ipaaca::converters::IUConverter;
//friend class ipaaca::converters::MessageConverter;
friend std::ostream& operator<<(std::ostream& os, const IUInterface& obj);
protected:
IPAACA_HEADER_EXPORT IUInterface();
public:
IPAACA_HEADER_EXPORT inline virtual ~IUInterface() { }
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _uid;
IPAACA_MEMBER_VAR_EXPORT revision_t _revision;
IPAACA_MEMBER_VAR_EXPORT std::string _category;
IPAACA_MEMBER_VAR_EXPORT std::string _payload_type; // default is taken from __ipaaca_static_option_default_payload_type
IPAACA_MEMBER_VAR_EXPORT std::string _owner_name;
IPAACA_MEMBER_VAR_EXPORT bool _committed;
IPAACA_MEMBER_VAR_EXPORT bool _retracted;
IPAACA_MEMBER_VAR_EXPORT IUAccessMode _access_mode;
IPAACA_MEMBER_VAR_EXPORT bool _read_only;
//std::shared_ptr<Buffer> _buffer;
IPAACA_MEMBER_VAR_EXPORT Buffer* _buffer;
IPAACA_MEMBER_VAR_EXPORT SmartLinkMap _links;
protected:
friend class Payload;
// Internal functions that perform the update logic,
// e.g. sending a notification across the network
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) = 0;
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name) = 0;
//void _set_buffer(std::shared_ptr<Buffer> buffer);
IPAACA_HEADER_EXPORT void _associate_with_buffer(Buffer* buffer);
IPAACA_HEADER_EXPORT void _set_buffer(Buffer* buffer);
IPAACA_HEADER_EXPORT void _set_uid(const std::string& uid);
IPAACA_HEADER_EXPORT void _set_owner_name(const std::string& owner_name);
protected:
// internal functions that do not emit update events
IPAACA_HEADER_EXPORT void _add_and_remove_links(const LinkMap& add, const LinkMap& remove) { _links._add_and_remove_links(add, remove); }
IPAACA_HEADER_EXPORT void _replace_links(const LinkMap& links) { _links._replace_links(links); }
public:
/// Return whether IU has been retracted
IPAACA_HEADER_EXPORT inline bool retracted() const { return _retracted; }
/// Return whether IU has already been published (is in a Buffer).
IPAACA_HEADER_EXPORT inline bool is_published() { return (_buffer != 0); }
/// Return auto-generated UID string (set during IU construction)
IPAACA_HEADER_EXPORT inline const std::string& uid() const { return _uid; }
/// Return current IU revision number (incremented for each update)
IPAACA_HEADER_EXPORT inline revision_t revision() const { return _revision; }
/// Return the IU category string (set during IU construction)
IPAACA_HEADER_EXPORT inline const std::string& category() const { return _category; }
/// Return the channel name the IU is resident on (set on publication)
IPAACA_HEADER_EXPORT const std::string& channel();
/// Return the payload type (default "JSON")
IPAACA_HEADER_EXPORT inline const std::string& payload_type() const { return _payload_type; }
/// Return the owner name (unique fully-qualified buffer name, set on publication)
IPAACA_HEADER_EXPORT inline const std::string& owner_name() const { return _owner_name; }
/// Return whether IU has been committed to (i.e. is complete, confirmed, and henceforth constant)
IPAACA_HEADER_EXPORT inline bool committed() const { return _committed; }
/// Return the access mode (not relevant for the time being)
IPAACA_HEADER_EXPORT inline IUAccessMode access_mode() const { return _access_mode; }
/// Return whether IU is read only (committed, a Message, or explicitly set read-only by owner)
IPAACA_HEADER_EXPORT inline bool read_only() const { return _read_only; }
//inline std::shared_ptr<Buffer> buffer() { return _buffer; }
/// Return owning buffer [CAVEAT: do not rely on this function for future code]
IPAACA_HEADER_EXPORT inline Buffer* buffer() const { return _buffer; }
/// Return the link set for an arbitrary link type (e.g. "grounded_in"), or EMPTY_LINK_SET
IPAACA_HEADER_EXPORT inline const LinkSet& get_links(std::string type) { return _links.get_links(type); }
/// Return the map of all defined links
IPAACA_HEADER_EXPORT inline const LinkMap& get_all_links() { return _links.get_all_links(); }
// Payload
/// Return the Payload object of this IU, overridden in the derived classes
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual Payload& payload() = 0;
/// Const version of payload()
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual const Payload& const_payload() const = 0;
// setters
/// Commit to an IU (only possible for the IU owner)
IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void commit() = 0;
// functions to modify and update links:
//IPAACA_HEADER_EXPORT void _publish_resend(std::shared_ptr<IU> iu, const std::string& hidden_scope_name);
/// Add a set of new UIDs for a specific link type
IPAACA_HEADER_EXPORT void add_links(const std::string& type, const LinkSet& targets, const std::string& writer_name = "");
/// Remove a set of UIDs from a link type
IPAACA_HEADER_EXPORT void remove_links(const std::string& type, const LinkSet& targets, const std::string& writer_name = "");
/// Bulk link modification function
IPAACA_HEADER_EXPORT void modify_links(const LinkMap& add, const LinkMap& remove, const std::string& writer_name = "");
/// Bulk link override function
IPAACA_HEADER_EXPORT void set_links(const LinkMap& links, const std::string& writer_name = "");
// (with cpp specific convenience functions:)
/// Convenience function (C++): add a single UID string to an arbitrary link set
IPAACA_HEADER_EXPORT void add_link(const std::string& type, const std::string& target, const std::string& writer_name = "");
/// Convenience function (C++): remove a single UID string from an arbitrary link set (if contained)
IPAACA_HEADER_EXPORT void remove_link(const std::string& type, const std::string& target, const std::string& writer_name = "");
typedef std::shared_ptr<IUInterface> ptr;
};//}}}
/** \brief Class of locally-owned IU objects.
*
* Use IU::create() (static) to create references to new IUs.
* Use IU::payload() to access the IUs payload object.
* Use OutputBuffer::add() to publish IUs.
*
* See IUInterface for a generic description of most user-space member functions.
*/
class IU: public IUInterface {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class ipaaca::backend::LocalServer;
public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected:
IPAACA_MEMBER_VAR_EXPORT Lock _revision_lock;
protected:
IPAACA_HEADER_EXPORT inline void _increase_revision_number() { _revision++; }
IPAACA_HEADER_EXPORT IU(const std::string& category, IUAccessMode access_mode=IU_ACCESS_PUSH, bool read_only=false, const std::string& payload_type="" ); // __ipaaca_static_option_default_payload_type
public:
IPAACA_HEADER_EXPORT inline ~IU() {
}
[[deprecated("Please use the new argument order: category, payload_type, read_only")]]
IPAACA_HEADER_EXPORT static std::shared_ptr<IU> create(const std::string& category, IUAccessMode access_mode, bool read_only=false, const std::string& payload_type="" );
IPAACA_HEADER_EXPORT static std::shared_ptr<IU> create(const std::string& category, const std::string& payload_type="", bool read_only=false);
IPAACA_HEADER_EXPORT inline Payload& payload() _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT void commit() _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT virtual void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT virtual void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT virtual void _internal_commit(const std::string& writer_name = "");
public:
typedef std::shared_ptr<IU> ptr;
};//}}}
/** \brief Class of locally-owned message objects ('one-shot' IUs).
*
* This class works the same as IU, except that it sets the internal
* flags so that it is received as a message (ephemeral object) on
* the remote sides, instead of a persistent objects.
*
* Likewise, it is not actually stored by OutputBuffer::add(), but just broadcast.
*
* See IUInterface for a generic description of most user-space member functions.
*
* \see IU, IUInterface
*/
class Message: public IU {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class ipaaca::backend::LocalServer;
protected:
IPAACA_HEADER_EXPORT Message(const std::string& category, IUAccessMode access_mode=IU_ACCESS_MESSAGE, bool read_only=true, const std::string& payload_type="" );
public:
IPAACA_HEADER_EXPORT inline ~Message() {
}
[[deprecated("Please use the new argument order: category, payload_type")]]
IPAACA_HEADER_EXPORT static std::shared_ptr<Message> create(const std::string& category, IUAccessMode access_mode, bool read_only=true, const std::string& payload_type="" );
IPAACA_HEADER_EXPORT static std::shared_ptr<Message> create(const std::string& category, const std::string& payload_type="");
protected:
IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _internal_commit(const std::string& writer_name = "");
public:
typedef std::shared_ptr<Message> ptr;
};//}}}
/// Copy of a remote IU, received in an InputBuffer. Setter functions call RPC over the backend (RSB). \b Note: Typically handled only as reference in a handler in user space.
class RemotePushIU: public IUInterface {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class ipaaca::converters::IUConverter;
//friend class ipaaca::converters::MessageConverter;
public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected:
IPAACA_HEADER_EXPORT RemotePushIU();
IPAACA_HEADER_EXPORT static std::shared_ptr<RemotePushIU> create();
public:
IPAACA_HEADER_EXPORT inline ~RemotePushIU() {
}
IPAACA_HEADER_EXPORT inline Payload& payload() _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT void commit() _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _apply_update(IUPayloadUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_commission();
IPAACA_HEADER_EXPORT void _apply_retraction();
typedef std::shared_ptr<RemotePushIU> ptr;
};//}}}
/// Copy of a remote Message, received in an InputBuffer. Setter functions all fail.\b Note: Typically handled only as reference in a handler in user space.
class RemoteMessage: public IUInterface {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class ipaaca::converters::IUConverter;
//friend class ipaaca::converters::MessageConverter;
public:
IPAACA_MEMBER_VAR_EXPORT Payload _payload;
protected:
IPAACA_HEADER_EXPORT RemoteMessage();
IPAACA_HEADER_EXPORT static std::shared_ptr<RemoteMessage> create();
public:
IPAACA_HEADER_EXPORT inline ~RemoteMessage() {
}
IPAACA_HEADER_EXPORT inline Payload& payload() _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; }
IPAACA_HEADER_EXPORT void commit() _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _apply_update(IUPayloadUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_commission();
IPAACA_HEADER_EXPORT void _apply_retraction();
typedef std::shared_ptr<RemoteMessage> ptr;
};//}}}
#ifdef IPAACA_BUILD_MOCK_OBJECTS
/// Mock IU for testing purposes. [INTERNAL]
class FakeIU: public IUInterface {//{{{
friend class Buffer;
friend class InputBuffer;
friend class OutputBuffer;
friend class ipaaca::converters::IUConverter;
//friend class ipaaca::converters::MessageConverter;
protected:
IPAACA_MEMBER_VAR_EXPORT Payload _payload;
IPAACA_HEADER_EXPORT FakeIU();
public:
IPAACA_HEADER_EXPORT static std::shared_ptr<FakeIU> create();
IPAACA_HEADER_EXPORT ~FakeIU();
IPAACA_HEADER_EXPORT Payload& payload() _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT const Payload& const_payload() const _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void commit() _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void add_fake_payload_item(const std::string& key, PayloadDocumentEntry::ptr entry);
protected:
IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_;
protected:
IPAACA_HEADER_EXPORT void _apply_update(IUPayloadUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update);
IPAACA_HEADER_EXPORT void _apply_commission();
IPAACA_HEADER_EXPORT void _apply_retraction();
public:
typedef std::shared_ptr<FakeIU> ptr;
};//}}}
#endif
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-locking.h
*
* \brief Header file for locking / mutexes.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_locking_h_INCLUDED__
#define __ipaaca_locking_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
/// Reentrant lock/mutex class
class Lock
{
protected:
std::recursive_mutex _mutex;
public:
IPAACA_HEADER_EXPORT inline Lock() {
}
IPAACA_HEADER_EXPORT inline ~Lock() {
}
IPAACA_HEADER_EXPORT inline void lock() {
_mutex.lock();
on_lock();
}
IPAACA_HEADER_EXPORT inline void unlock() {
on_unlock();
_mutex.unlock();
}
IPAACA_HEADER_EXPORT virtual inline void on_lock() {
}
IPAACA_HEADER_EXPORT virtual inline void on_unlock() {
}
};
/** \brief Stack-based lock holder.
*
* Stack-based lock holder. Create in a new stack frame
* (i.e. {}-block) and it will obtain the lock and
* auto-release in on exiting the stack frame.
*/
class Locker
{
protected:
IPAACA_MEMBER_VAR_EXPORT Lock* _lock;
private:
IPAACA_HEADER_EXPORT inline Locker(): _lock(NULL) { } // not available
public:
IPAACA_HEADER_EXPORT inline Locker(Lock& lock): _lock(&lock) {
_lock->lock();
}
IPAACA_HEADER_EXPORT inline ~Locker() {
_lock->unlock();
}
};
/** \brief Locker for existing pthread mutexes.
*
* Stack-based lock holder for existing pthread_mutex_t mutexes.
*
* \see Locker
*/
#if _WIN32 || _WIN64
// nothing for Windows
#else
#include <pthread.h>
class PthreadMutexLocker
{
protected:
IPAACA_MEMBER_VAR_EXPORT pthread_mutex_t* _lock;
private:
IPAACA_HEADER_EXPORT inline PthreadMutexLocker(): _lock(NULL) { } // not available
public:
IPAACA_HEADER_EXPORT inline PthreadMutexLocker(pthread_mutex_t* lock): _lock(lock) {
if (!lock) throw Exception("PthreadMutexLocker got a NULL mutex!");
pthread_mutex_lock(_lock);
}
IPAACA_HEADER_EXPORT inline ~PthreadMutexLocker() {
pthread_mutex_unlock(_lock);
}
};
#endif
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-payload.h
*
* \brief Header file for IU payload functionality.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_payload_h_INCLUDED__
#define __ipaaca_payload_h_INCLUDED__
#include <typeinfo>
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
// casting operators from Value&
/// 'Smart' type conversions, allowing for some leeway type-wise (e.g. string "1.3" can be successfully cast to double or long). Used by PayloadEntryProxy.
template<typename T> T json_value_cast(const rapidjson::Value&);
template<typename T> T json_value_cast(const rapidjson::Value* value) { if (!value) return T(); return json_value_cast<T>(*value); }
template<> IPAACA_HEADER_EXPORT long json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT int json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT double json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT bool json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT std::string json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT std::vector<std::string> json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT std::list<std::string> json_value_cast(const rapidjson::Value&);
template<> IPAACA_HEADER_EXPORT std::map<std::string, std::string> json_value_cast(const rapidjson::Value&);
// helpers to set Value& from various standard types
//IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, T t);
/// Setter to store int into json value, used by PayloadEntryProxy.
IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, int);
/// Setter to store int into json value, used by PayloadEntryProxy.
IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, long);
/// Setter to store long into json value, used by PayloadEntryProxy.
IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, double);
/// Setter to store double into json value, used by PayloadEntryProxy.
IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, bool);
/// Setter to store bool into json value, used by PayloadEntryProxy.
IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::string&);
/// Setter to store std::string into json value, used by PayloadEntryProxy.
IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const char*);
// helpers to set Value& from several standard containers containing the above standard types
/// Setter to store a vector of supported basic types into json value, used by PayloadEntryProxy.
template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::vector<T>& ts)
{
valueobject.SetArray();
for (auto& val: ts) {
rapidjson::Value newv;
pack_into_json_value(newv, allocator, val);
valueobject.PushBack(newv, allocator);
}
}
/// Setter to store a list of supported basic types into json value, used by PayloadEntryProxy.
template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::list<T>& ts)
{
valueobject.SetArray();
for (auto& val: ts) {
rapidjson::Value newv;
pack_into_json_value(newv, allocator, val);
valueobject.PushBack(newv, allocator);
}
}
/// Setter to store a map of string -> supported basic types into json value, used by PayloadEntryProxy.
template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::map<std::string, T>& ts)
{
valueobject.SetObject();
for (auto& val: ts) {
rapidjson::Value key;
key.SetString(val.first, allocator);
rapidjson::Value newv;
pack_into_json_value(newv, allocator, val.second);
valueobject.AddMember(key, newv, allocator);
}
}
/// Single payload entry wrapping a rapidjson::Document with some conversion glue. Also handles copy-on-write Document cloning. <b>Internal type</b> - users generally do not see this.
class PayloadDocumentEntry//{{{
{
friend std::ostream& operator<<(std::ostream& os, std::shared_ptr<PayloadDocumentEntry> entry);
public:
IPAACA_MEMBER_VAR_EXPORT ipaaca::Lock lock;
IPAACA_MEMBER_VAR_EXPORT bool modified;
IPAACA_MEMBER_VAR_EXPORT rapidjson::Document document;
IPAACA_HEADER_EXPORT inline PayloadDocumentEntry(): modified(false) { }
IPAACA_HEADER_EXPORT inline ~PayloadDocumentEntry() { }
IPAACA_HEADER_EXPORT std::string to_json_string_representation();
IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> from_json_string_representation(const std::string& input);
IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> from_unquoted_string_value(const std::string& input);
IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> create_null();
IPAACA_HEADER_EXPORT std::shared_ptr<PayloadDocumentEntry> clone();
IPAACA_HEADER_EXPORT rapidjson::Value& get_or_create_nested_value_from_proxy_path(PayloadEntryProxy* pep);
typedef std::shared_ptr<PayloadDocumentEntry> ptr;
};
//}}}
typedef std::map<std::string, PayloadDocumentEntry::ptr> PayloadDocumentStore;
/** \brief Central class containing the user-set payload of any IUInterface class (IU, Message, RemotePushIU or RemoteMessage)
*
* Obtained by calling payload() on any IUInterface derived object. Created during IU creation.
*/
class Payload: public Lock //{{{
{
friend std::ostream& operator<<(std::ostream& os, const Payload& obj);
friend class IUInterface;
friend class IU;
friend class Message;
friend class RemotePushIU;
friend class RemoteMessage;
friend class ipaaca::converters::IUConverter;
//friend class ipaaca::converters::MessageConverter;
friend class ipaaca::backend::LocalServer;
friend class PayloadEntryProxy;
friend class PayloadIterator;
friend class FakeIU;
protected:
IPAACA_MEMBER_VAR_EXPORT std::string _owner_name;
IPAACA_MEMBER_VAR_EXPORT PayloadDocumentStore _document_store;
IPAACA_MEMBER_VAR_EXPORT std::weak_ptr<IUInterface> _iu;
IPAACA_MEMBER_VAR_EXPORT Lock _payload_operation_mode_lock; //< enforcing atomicity wrt the bool flag below
IPAACA_MEMBER_VAR_EXPORT bool _update_on_every_change; //< true: batch update not active; false: collecting updates (payload locked)
IPAACA_MEMBER_VAR_EXPORT std::map<std::string, PayloadDocumentEntry::ptr> _collected_modifications;
IPAACA_MEMBER_VAR_EXPORT std::vector<std::string> _collected_removals; // TODO use set later? cf. IU, too
IPAACA_MEMBER_VAR_EXPORT std::string _batch_update_writer_name;
protected:
/// inherited from ipaaca::Lock, starting batch update collection mode
IPAACA_HEADER_EXPORT void on_lock() override;
/// inherited from ipaaca::Lock, finishing batch update collection mode
IPAACA_HEADER_EXPORT void on_unlock() override;
/// thread ID for current write access (to let that thread read from cache and others from old payload)
IPAACA_MEMBER_VAR_EXPORT std::string _writing_thread_id;
protected:
IPAACA_HEADER_EXPORT void initialize(std::shared_ptr<IUInterface> iu);
IPAACA_HEADER_EXPORT inline void _set_owner_name(const std::string& name) { _owner_name = name; }
IPAACA_HEADER_EXPORT void _remotely_enforced_wipe();
IPAACA_HEADER_EXPORT void _remotely_enforced_delitem(const std::string& k);
IPAACA_HEADER_EXPORT void _remotely_enforced_setitem(const std::string& k, PayloadDocumentEntry::ptr entry);
IPAACA_HEADER_EXPORT void _internal_replace_all(const std::map<std::string, PayloadDocumentEntry::ptr>& new_contents, const std::string& writer_name="");
IPAACA_HEADER_EXPORT void _internal_merge(const std::map<std::string, PayloadDocumentEntry::ptr>& contents_to_merge, const std::string& writer_name="");
IPAACA_HEADER_EXPORT void _internal_set(const std::string& k, PayloadDocumentEntry::ptr v, const std::string& writer_name="");
IPAACA_HEADER_EXPORT void _internal_remove(const std::string& k, const std::string& writer_name="");
IPAACA_HEADER_EXPORT void _internal_merge_and_remove(const std::map<std::string, PayloadDocumentEntry::ptr>& contents_to_merge, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="");
public:
IPAACA_HEADER_EXPORT inline Payload(): _batch_update_writer_name(""), _update_on_every_change(true) { }
IPAACA_HEADER_EXPORT inline const std::string& owner_name() { return _owner_name; }
// access
/// Obtain a payload item by name as a PayloadEntryProxy (returning null-type proxy if undefined)
IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const std::string& key);
/// Legacy / convenience function: interpret the payload map as a map string->string (casting all entries to string)
IPAACA_HEADER_EXPORT operator std::map<std::string, std::string>();
/// remove a single payload entry
IPAACA_HEADER_EXPORT inline void remove(const std::string& k) { _internal_remove(k); }
/// Legacy / convenience function: set the whole payload map from a map string->string (all JSON types are also set as string, no interpretation)
IPAACA_HEADER_EXPORT void set(const std::map<std::string, std::string>& all_elems);
protected:
/// set or overwrite a single payload entry with a PayloadDocumentEntry object (used by PayloadEntryProxy::operator=()).
IPAACA_HEADER_EXPORT inline void set(const std::string& k, PayloadDocumentEntry::ptr entry) { _internal_set(k, entry); }
IPAACA_HEADER_EXPORT PayloadDocumentEntry::ptr get_entry(const std::string& k); // json, changed str to proxy here, too
public:
[[deprecated("Use operator[] and operator std::string() instead")]]
/// Read a single entry as string [DEPRECATED] (use string conversion in PayloadEntryProxy instead)
IPAACA_HEADER_EXPORT std::string get(const std::string& k);
protected:
IPAACA_MEMBER_VAR_EXPORT unsigned long internal_revision;
IPAACA_MEMBER_VAR_EXPORT inline void mark_revision_change() { internal_revision++; }
IPAACA_HEADER_EXPORT inline bool revision_changed(unsigned long reference_revision) { return internal_revision != reference_revision; }
public:
/// obtain a standard iterator marking the first entry in the payload
IPAACA_HEADER_EXPORT PayloadIterator begin();
/// obtain a standard iterator past the last entry in the payload
IPAACA_HEADER_EXPORT PayloadIterator end();
typedef std::shared_ptr<Payload> ptr;
};//}}}
/** \brief Standard iterator for Payload (example below)
*
* \b Examples:
* <pre>
* // Print all key-value pairs from a payload (C++11)
* for (auto kv_pair: myiu->payload()) {
* std::cout << kv_pair.first << " -> " << (std::string) kv_pair.second << std::endl;
* }
* </pre>
*
*/
class PayloadIterator//{{{
{
friend class Payload;
friend std::ostream& operator<<(std::ostream& os, const PayloadIterator& iter);
protected:
IPAACA_MEMBER_VAR_EXPORT Payload* _payload;
IPAACA_MEMBER_VAR_EXPORT unsigned long reference_payload_revision;
IPAACA_MEMBER_VAR_EXPORT PayloadDocumentStore::iterator raw_iterator;
protected:
IPAACA_HEADER_EXPORT PayloadIterator(Payload* payload, PayloadDocumentStore::iterator&& pl_iter ); //, bool is_end);
public:
IPAACA_HEADER_EXPORT PayloadIterator(const PayloadIterator& iter);
IPAACA_HEADER_EXPORT PayloadIterator& operator++();
IPAACA_HEADER_EXPORT std::pair<std::string, PayloadEntryProxy> operator*();
IPAACA_HEADER_EXPORT std::shared_ptr<std::pair<std::string, PayloadEntryProxy> > operator->();
IPAACA_HEADER_EXPORT bool operator==(const PayloadIterator& ref);
IPAACA_HEADER_EXPORT bool operator!=(const PayloadIterator& ref);
};
//}}}
/// Iterator over a payload entry that is a json map-type object (returned type during dereferencing: pair<string, PayloadEntryProxy>)
class PayloadEntryProxyMapIterator//{{{
{
public:
typedef rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>::ConstMemberIterator RawIterator;
protected:
IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy;
IPAACA_MEMBER_VAR_EXPORT RawIterator raw_iterator;
public:
IPAACA_HEADER_EXPORT PayloadEntryProxyMapIterator(PayloadEntryProxy* proxy, RawIterator&& raw_iter);
IPAACA_HEADER_EXPORT PayloadEntryProxyMapIterator& operator++();
IPAACA_HEADER_EXPORT std::pair<std::string, PayloadEntryProxy> operator*();
IPAACA_HEADER_EXPORT std::shared_ptr<std::pair<std::string, PayloadEntryProxy> > operator->();
IPAACA_HEADER_EXPORT bool operator==(const PayloadEntryProxyMapIterator& other_iter);
IPAACA_HEADER_EXPORT bool operator!=(const PayloadEntryProxyMapIterator& other_iter);
};
//}}}
/// Iterator over a payload entry that is a json list-type object (returned type during dereferencing: PayloadEntryProxy)
class PayloadEntryProxyListIterator//{{{
{
protected:
IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy;
IPAACA_MEMBER_VAR_EXPORT size_t current_idx;
IPAACA_MEMBER_VAR_EXPORT size_t size;
public:
IPAACA_HEADER_EXPORT PayloadEntryProxyListIterator(PayloadEntryProxy* proxy, size_t idx, size_t size);
IPAACA_HEADER_EXPORT PayloadEntryProxyListIterator& operator++();
IPAACA_HEADER_EXPORT PayloadEntryProxy operator*();
IPAACA_HEADER_EXPORT std::shared_ptr<PayloadEntryProxy> operator->();
IPAACA_HEADER_EXPORT bool operator==(const PayloadEntryProxyListIterator& other_iter);
IPAACA_HEADER_EXPORT bool operator!=(const PayloadEntryProxyListIterator& other_iter);
};
//}}}
/// Interpretation of a variant json value as a map-type object
class PayloadEntryProxyMapDecorator//{{{
{
public:
IPAACA_HEADER_EXPORT inline PayloadEntryProxyMapDecorator(PayloadEntryProxy* proxy_): proxy(proxy_) { }
IPAACA_HEADER_EXPORT PayloadEntryProxyMapIterator begin();
IPAACA_HEADER_EXPORT PayloadEntryProxyMapIterator end();
protected:
IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy;
};
//}}}
/// Interpretation of a variant json value as a list-type object
class PayloadEntryProxyListDecorator//{{{
{
public:
IPAACA_HEADER_EXPORT inline PayloadEntryProxyListDecorator(PayloadEntryProxy* proxy_): proxy(proxy_) { }
IPAACA_HEADER_EXPORT PayloadEntryProxyListIterator begin();
IPAACA_HEADER_EXPORT PayloadEntryProxyListIterator end();
protected:
IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* proxy;
};
//}}}
/** \brief Reference to an existent or nonexistent payload entry (or a value deeper in the json tree) - examples below:
*
* This class is returned by IUInterface::operator[].
* The proxy handles automatic type conversions, requests remote changes of payloads, and enables navigation into and iteration over structured json objects.
*
* \b Examples (reading):
*
* <code>std::string received_name = iu->payload()["name"];</code> // implicit conversion using operator string()
*
* <code>std::vector<double> vd = iu->payload()["double_list"];</code> // some standard container types also supported
*
* <code>auto p = iu->payload()["otherKey"];</code> // auto type is PayloadEntryProxy (conversion is on-demand)
*
* <code>for (auto val: iu->payload()["my_list"].as_list()) { ... }</code> // as_list is required to select list-type iteration (value type in iteration remains variant)
*
* <code>for (auto k_v_pair: iu->payload()["my_map"].as_map()) { ... }</code> // as_map is required to select map-type iteration (value type in iteration is a pair, second part remains variant)
*
* \b Examples (writing):
*
* <code>iu->payload()["my_new_item"] = "new value";</code> // most basic operation, set string value
*
* <code>iu->payload()["double_list"][0] = 100.0;</code> // accessing and updating an item in a list
*
* <code>iu->payload()["name_list"] = std::list<std::string>{"Alpha", "Bravo", "Charlie"};</code> // set from basic uniform containers
*
* <code>iu->payload()["name_list"].push_back("--- adding some numbers below ---");</code> // append a supported value to an existing list
*
* <code>iu->payload()["name_list"].extend(iu->payload()["double_list"]);</code> // extend list by items; \b Note: all setters also accept proxies as source values, creating copies of values
*/
class PayloadEntryProxy//{{{
{
friend class Payload;
friend class PayloadIterator;
friend class PayloadDocumentEntry;
friend class PayloadEntryProxyListDecorator;
friend class PayloadEntryProxyListIterator;
friend class PayloadEntryProxyMapDecorator;
friend class PayloadEntryProxyMapIterator;
friend std::ostream& operator<<(std::ostream& os, const PayloadEntryProxy& proxy);
public:
/// Select map-style iteration for this proxy (to select iterator content type). Will throw if not actually map-type. See example in the class description.
IPAACA_HEADER_EXPORT PayloadEntryProxyMapDecorator as_map();
/// Select list-style iteration for this proxy (to select iterator content type). Will throw if not actually list-type. See example in the class description.
IPAACA_HEADER_EXPORT PayloadEntryProxyListDecorator as_list();
protected:
IPAACA_MEMBER_VAR_EXPORT Payload* _payload;
IPAACA_MEMBER_VAR_EXPORT std::string _key;
// new json stuff / hierarchical navigation
IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* parent; ///< Parent proxy (up to document root -> then null)
IPAACA_MEMBER_VAR_EXPORT PayloadDocumentEntry::ptr document_entry; // contains lock and json Doc
IPAACA_MEMBER_VAR_EXPORT bool existent; ///< Whether Value exists already (or else 'blindly' navigated)
IPAACA_MEMBER_VAR_EXPORT bool addressed_as_array; ///< Whether long or string navigation was used
IPAACA_MEMBER_VAR_EXPORT long addressed_index; ///< Index that was used in list-style access
IPAACA_MEMBER_VAR_EXPORT std::string addressed_key; ///< Key that was used in map-style access
/// currently navigated value in json tree (or a new Null value)
IPAACA_MEMBER_VAR_EXPORT rapidjson::Value* json_value; ///< json value that corresponds to the current navigation (or nullptr)
protected:
// set internal json value object
void set_json_value(rapidjson::Value* json_value, const std::string& diag) {
IPAACA_DEBUG("Set json_value of " << _key << " to ptr " << (off_t) json_value << " - reason: " << diag)
this->json_value = json_value;
}
// constructor to create a new top-most parent proxy (from a payload key)
IPAACA_HEADER_EXPORT PayloadEntryProxy(Payload* payload, const std::string& key);
// constructors for navigation through objects
IPAACA_HEADER_EXPORT PayloadEntryProxy(PayloadEntryProxy* parent, const std::string& addressed_key);
IPAACA_HEADER_EXPORT PayloadEntryProxy(PayloadEntryProxy* parent, size_t addressed_index);
public:
/// Return number of contained items (or 0 for non-container types)
IPAACA_HEADER_EXPORT size_t size();
/// Return whether value corresponds to json 'null'; also true if value is nonexistent so far (e.g. navigated to new map entry)
IPAACA_HEADER_EXPORT bool is_null();
/// Return whether value is of string type
IPAACA_HEADER_EXPORT bool is_string();
/// Return whether value is of a numerical type
IPAACA_HEADER_EXPORT bool is_number();
/// Return whether value is of list type
IPAACA_HEADER_EXPORT bool is_list();
/// Return whether value is of map type
IPAACA_HEADER_EXPORT bool is_map();
public:
/// Array-style navigation over json value
IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](size_t index); // array-style navigation
/// Array-style navigation over json value (added to catch [0])
IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](int index); // int is UNFORTUNATELY required to catch
// [0] (addressing using literal zero)
// because ambiguity with const char*
// arises if only [](size_t) is provided.
// size_t is obviously superior ...
// TODO: remove if better solution known
/// Dict-style navigation over json value
IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const std::string& key); // dict-style navigation
/// Dict-style navigation over json value
IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const char* key);
//
/// Set or overwrite some portion of a payload from the point navigated to
template<typename T> PayloadEntryProxy& operator=(T t)
{
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& newval = new_entry->get_or_create_nested_value_from_proxy_path(this);
pack_into_json_value(newval, new_entry->document.GetAllocator(), t);
_payload->set(_key, new_entry);
return *this;
}
/// Value comparison with other proxy contents
IPAACA_HEADER_EXPORT inline bool operator==(const PayloadEntryProxy& otherproxy) { return (json_value && otherproxy.json_value && ((*json_value)==*(otherproxy.json_value))); }
/// Value comparison with other proxy contents
IPAACA_HEADER_EXPORT inline bool operator!=(const PayloadEntryProxy& otherproxy) { return !operator==(otherproxy); }
/// Value comparison with supported basic types
template<typename T> bool operator==(T othervalue)
{
if (!json_value) return false;
try {
return json_value_cast<T>(*json_value) == othervalue;
} catch(PayloadTypeConversionError& ex) {
// assume conversion error = type mismatch = unequal
return false;
}
}
/// Value comparison with supported basic types
template<typename T> bool operator!=(T othervalue) { return !operator==(othervalue); }
/// Value comparison with char* (required to be explicitly added)
IPAACA_HEADER_EXPORT inline bool operator==(const char* othervalue)
{
if (!json_value) return false;
return json_value_cast<std::string>(*json_value) == othervalue;
}
/// Value comparison with char* (required to be explicitly added)
IPAACA_HEADER_EXPORT inline bool operator!=(const char* othervalue) { return !operator==(othervalue); }
/// Copy value from below other json node, preserving types
IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const PayloadEntryProxy& otherproxy);
/// Conversion to std::string (explicit or implicit)
IPAACA_HEADER_EXPORT operator std::string();
/// Conversion to int (explicit or implicit)
IPAACA_HEADER_EXPORT operator int();
/// Conversion to long (explicit or implicit)
IPAACA_HEADER_EXPORT operator long();
/// Conversion to double (explicit or implicit)
IPAACA_HEADER_EXPORT operator double();
/// Conversion to bool (explicit or implicit)
IPAACA_HEADER_EXPORT operator bool();
/// Conversion to uniform std::vector of supported basic type
template<typename Inner> operator std::vector<Inner>() {
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
std::vector<Inner> result;
for (auto it = json_value->Begin(); it != json_value->End(); ++it) {
result.push_back( json_value_cast<Inner>(*it) );
}
return result;
}
/// Conversion to uniform std::list of supported basic type
template<typename Inner> operator std::list<Inner>() {
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
std::list<Inner> result;
for (auto it = json_value->Begin(); it != json_value->End(); ++it) {
result.push_back( json_value_cast<Inner>(*it) );
}
return result;
}
/// Conversion to uniform std::map of string -> supported basic type
template<typename Inner> operator std::map<std::string, Inner>() {
if ((!json_value) || (!json_value->IsObject())) throw PayloadAddressingError();
std::map<std::string, Inner> result;
for (auto it = json_value->MemberBegin(); it != json_value->MemberEnd(); ++it) {
result[std::string(it->name.GetString())] = json_value_cast<Inner>(it->value);
}
return result;
}
// TODO maybe remove these deprecated converters later
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator std::string() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT std::string to_str();
//long to_int() { return operator long(); ;
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator int() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT int to_int();
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator long() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT long to_long();
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator double() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT double to_float();
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator double() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT double to_double();
/// [DECPRECATED] use normal type conversion syntax instead
[[deprecated("Use operator bool() instead (i.e. explicit or implicit cast)")]]
IPAACA_HEADER_EXPORT bool to_bool();
/// Append a supported type to a list-type payload value
template<typename T> void push_back(T t)
{
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& list = new_entry->get_or_create_nested_value_from_proxy_path(this);
rapidjson::Value newval;
pack_into_json_value(newval, new_entry->document.GetAllocator(), t);
list.PushBack(newval, new_entry->document.GetAllocator());
_payload->set(_key, new_entry);
}
/// Append the value of another proxy (or a null value) to a list-type value
IPAACA_HEADER_EXPORT void push_back(const PayloadEntryProxy& otherproxy)
{
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& list = new_entry->get_or_create_nested_value_from_proxy_path(this);
rapidjson::Value newval;
auto valueptr = otherproxy.json_value;
if (valueptr) { // only set if value is valid, keep default null value otherwise
newval.CopyFrom(*valueptr, new_entry->document.GetAllocator());
}
list.PushBack(newval, new_entry->document.GetAllocator());
_payload->set(_key, new_entry);
}
/// Extend a list-type payload value with a vector containing items of a supported type
template<typename T> void extend(const std::vector<T>& ts)
{
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& list = new_entry->get_or_create_nested_value_from_proxy_path(this);
for (auto& t: ts) {
rapidjson::Value newval;
pack_into_json_value(newval, new_entry->document.GetAllocator(), t);
list.PushBack(newval, new_entry->document.GetAllocator());
}
_payload->set(_key, new_entry);
}
/// Extend a list-type payload value with a list containing items of a supported type
template<typename T> void extend(const std::list<T>& ts)
{
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& list = new_entry->get_or_create_nested_value_from_proxy_path(this);
for (auto& t: ts) {
rapidjson::Value newval;
pack_into_json_value(newval, new_entry->document.GetAllocator(), t);
list.PushBack(newval, new_entry->document.GetAllocator());
}
_payload->set(_key, new_entry);
}
/// Extend a list-type payload value with items (copies) from another list-type value
IPAACA_HEADER_EXPORT void extend(const PayloadEntryProxy& otherproxy)
{
if ((!json_value) || (!json_value->IsArray())) throw PayloadAddressingError();
if ((!otherproxy.json_value) || (!(otherproxy.json_value->IsArray()))) throw PayloadAddressingError();
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& list = new_entry->get_or_create_nested_value_from_proxy_path(this);
for (size_t i=0; i<otherproxy.json_value->Size(); ++i) {
rapidjson::Value newval;
rapidjson::Value& value = (*(otherproxy.json_value))[i];
newval.CopyFrom(value, new_entry->document.GetAllocator());
list.PushBack(newval, new_entry->document.GetAllocator());
}
_payload->set(_key, new_entry);
}
};
//}}}
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
/**
* \file ipaaca-string_utils.h
*
* \brief Header file for data and exception types and helper functions.
*
* Users should not include this file directly, but use ipaaca.h
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __ipaaca_string_utils_h_INCLUDED__
#define __ipaaca_string_utils_h_INCLUDED__
#ifndef __ipaaca_h_INCLUDED__
#error "Please do not include this file directly, use ipaaca.h instead"
#endif
// in ipaaca-string-utils.cc
// additional misc functions ( String splitting / joining )//{{{
IPAACA_HEADER_EXPORT std::string str_trim(const std::string &s);
IPAACA_HEADER_EXPORT std::string str_join(const std::set<std::string>& set,const std::string& sep);
IPAACA_HEADER_EXPORT std::string str_join(const std::vector<std::string>& vec,const std::string& sep);
IPAACA_HEADER_EXPORT int str_split_wipe(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters );
IPAACA_HEADER_EXPORT int str_split_append(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters );
//}}}
#endif
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* 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.h
*
* \brief Central header file for IPAACA-C++.
*
* This is the central header file for the C++ version of IPAACA. Users should <b>include this file only.</b>
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
/**
\mainpage Documentation for IPAACA-C++
This is the automatically generated documentation for the C++ implementation of IPAACA.
Protocol version: $(IPAACA_PROTOCOL_VERSION_MAJOR).$(IPAACA_PROTOCOL_VERSION_MINOR) \n
Release number: $(IPAACA_CPP_RELEASE_NUMBER) \n
Release date: $(IPAACA_CPP_RELEASE_DATE)
<b>IPAACA, the Incremental Processing Architecture for Artificial Conversational Agents, is available via <a href="https://opensource.cit-ec.de/projects/ipaaca/wiki"><b>its project page on CITEC Open Source</b></a>.</b>
IPAACA is (c) 2009-2022 Social Cognitive Systems Group, CITEC, Bielefeld University, Germany
The corresponding maintainer of this C++ version is Ramin Yaghoubzadeh Torky, ryaghoubzadeh@uni-bielefeld.de
<h3>List of most relevant entry points for application developers:</h3>
Buffers: InputBuffer, OutputBuffer
IUs: IUInterface, IU, Message
IU handling (user-set): #IUEventHandlerFunction
IU payload contents: Payload, PayloadEntryProxy
<h3>Short examples:</h3>
<h4>Encapsulated listener</h4>
<pre>
#include <ipaaca/ipaaca.h>
class ReceiverCpp {
public:
void handle_iu_inbuf(ipaaca::IUInterface::ptr iu, ipaaca::IUEventType etype, bool local)
{
// Inspect category and IUEventType (ADDED, UPDATED...)
std::cout << ipaaca::iu_event_type_to_str(etype) << " category=" << iu->category() << " uid=" << iu->uid() << std::endl;
// Access payload
for (auto kv : iu->payload()) {
std::cout << "Payload entry '" << kv.first << "': " << ((std::string) kv.second) << std::endl;
}
// Access any links
auto links = iu->get_all_links();
for (auto kv : iu->get_all_links()) {
std::cout << "'" << kv.first << "' links to these IUs: ";
for (const auto& lnk : kv.second) {
std::cout << lnk << " ";
}
std::cout << std::endl;
}
}
int run()
{
auto ib = ipaaca::InputBuffer::create("myRecvProgName", std::set<std::string>{"myCategory"});
ib->register_handler(IPAACA_BIND_CLASS_HANDLER(&ReceiverCpp::handle_iu_inbuf, this)) // bind to member
std::cout << "Listening for all IU events (until Ctrl-C) ..." << std::endl;
while (true) {
sleep(5);
}
return 0;
}
};
int main(int argc, char** argv)
{
ipaaca::__ipaaca_static_option_log_level = IPAACA_LOG_LEVEL_DEBUG; // if you want this
ReceiverCpp rcpp;
rcpp.run();
}
</pre>
<h4>Minimal sender</h4>
<pre>
#include <ipaaca/ipaaca.h>
int main(int argc, char** argv)
{
auto out_buf = ipaaca::OutputBuffer::create("myProgramName");
auto iu = ipaaca::Message::create("myCategory");
iu->payload()["test"] = 123; // NOTE: see also #PayloadEntryProxy
out_buf->add(iu); // will be broadcast now
return 0;
}
</pre>
*/
#ifndef __ipaaca_h_INCLUDED__
#define __ipaaca_h_INCLUDED__
/// ipaaca/IU/RSB protocol major version number
#define IPAACA_PROTOCOL_VERSION_MAJOR 4
/// ipaaca/IU/RSB protocol minor version number
#define IPAACA_PROTOCOL_VERSION_MINOR 1
/// running release number of ipaaca-c++
#define IPAACA_CPP_RELEASE_NUMBER 17
/// date of last release number increment
#define IPAACA_CPP_RELEASE_DATE "2019-02-14"
#ifndef __FUNCTION_NAME__
#if _WIN32 || _WIN64 // Windows
#define __FUNCTION_NAME__ __FUNCTION__
#else // POSIX
#define __FUNCTION_NAME__ __func__
#endif
#endif
#if _WIN32 || _WIN64
#define IPAACA_SYSTEM_DEPENDENT_CLASS_NAME(c) "class "##c
#else
#define IPAACA_SYSTEM_DEPENDENT_CLASS_NAME(c) c
#endif
#if _WIN32 || _WIN64
#if defined(IPAACA_STATIC_BINARY)
#define IPAACA_EXPORT
#define IPAACA_HEADER_EXPORT
#define IPAACA_MEMBER_VAR_EXPORT
#else
#if defined(ipaaca_EXPORTS)
#define IPAACA_EXPORT
#define IPAACA_HEADER_EXPORT __declspec(dllexport)
#define IPAACA_MEMBER_VAR_EXPORT
#else
#define IPAACA_EXPORT
#define IPAACA_HEADER_EXPORT __declspec(dllimport)
#define IPAACA_MEMBER_VAR_EXPORT
#endif
#endif
#else
#define IPAACA_EXPORT
#define IPAACA_HEADER_EXPORT
#define IPAACA_MEMBER_VAR_EXPORT
#endif
// retrieve basename of source files for more readable logging
#define __FILE_BASENAME__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/')+1 : __FILE__)
#if _WIN32 || _WIN64
#define _IPAACA_LOG_COLOR_NORMAL ""
#define _IPAACA_LOG_COLOR_DEBUG ""
#define _IPAACA_LOG_COLOR_WARN ""
#define _IPAACA_LOG_COLOR_ERROR ""
#else
#define _IPAACA_LOG_COLOR_NORMAL "\033[m"
#define _IPAACA_LOG_COLOR_DEBUG "\033[37m"
#define _IPAACA_LOG_COLOR_WARN "\033[38;5;208m"
#define _IPAACA_LOG_COLOR_ERROR "\033[38;5;196m"
#endif
#ifdef IPAACA_DEBUG_MESSAGES
// Full debug messages mode
#define IPAACA_DEBUG(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_DEBUG) { std::cout << _IPAACA_LOG_COLOR_DEBUG << "[Debug] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- " << i << _IPAACA_LOG_COLOR_NORMAL << std::endl; }
#define IPAACA_IMPLEMENT_ME if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_INFO) { std::cout << "[Info] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- IMPLEMENT ME" << std::endl; }
#define IPAACA_TODO(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_INFO) { std::cout << "[Info] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- TODO: " << i << std::endl; }
#else
#define IPAACA_DEBUG(i) ;
#define IPAACA_IMPLEMENT_ME ;
#define IPAACA_TODO(i) ;
#endif
// Always compile in info and above, even if debug messages disabled.
// You can set __ipaaca_static_option_log_level (e.g. IPAACA_LOG_LEVEL_NONE for silence).
#define IPAACA_INFO(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_INFO) { std::cout << "[Info] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- " << i << std::endl; }
#define IPAACA_WARNING(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_WARNING) { std::cout << _IPAACA_LOG_COLOR_WARN << "[WARN] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- WARNING: " << i << _IPAACA_LOG_COLOR_NORMAL << std::endl; }
#define IPAACA_ERROR(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_ERROR) { std::cout << _IPAACA_LOG_COLOR_ERROR << "[ERROR] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- ERROR: " << i << _IPAACA_LOG_COLOR_NORMAL << std::endl; }
#define IPAACA_CRITICAL(i) if (__ipaaca_static_option_log_level>=IPAACA_LOG_LEVEL_CRITICAL) { std::cout << _IPAACA_LOG_COLOR_ERROR << "[CRITICAL] " << __FILE_BASENAME__ << ":" << __LINE__ << ": " << __FUNCTION_NAME__ << "() -- CRITICAL: " << i << _IPAACA_LOG_COLOR_NORMAL << std::endl; }
// new json-based payload API, used in several classes
#define RAPIDJSON_HAS_STDSTRING 1
#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include <cstdio>
/// marking pure virtual functions for extra readability
#define _IPAACA_ABSTRACT_
#define _IPAACA_OVERRIDE_ override
/// value to return when reading nonexistant payload keys
#define IPAACA_PAYLOAD_DEFAULT_STRING_VALUE ""
// seconds until remote writes time out
#define IPAACA_REMOTE_SERVER_TIMEOUT 2.0
#include <iostream>
#include <fstream>
// for logger
#include <iomanip>
#if _WIN32 || _WIN64
// for Windows
// time
#include <time.h>
// and env
#define IPAACA_SETENV(k, v) _putenv_s(k, v);
#else
// for Linux and MacOS
// time
#include <sys/time.h>
// and env
#define IPAACA_SETENV(k, v) setenv(k, v, 1);
#endif
#include <cstdlib>
#if _WIN32 || _WIN64
#include <rpc.h>
#else
#include <uuid/uuid.h>
#include <glob.h>
#endif
#ifndef Q_MOC_RUN
#include <memory>
#include <functional>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>
#endif
#include <ipaaca/ipaaca.pb.h>
#include <set>
#include <list>
#include <algorithm>
#include <utility>
#include <initializer_list>
namespace ipaaca {
#include <ipaaca/ipaaca-definitions.h>
#include <ipaaca/ipaaca-forwards.h>
#include <ipaaca/ipaaca-errors.h>
#include <ipaaca/ipaaca-initializer.h>
#include <ipaaca/ipaaca-locking.h>
#include <ipaaca/ipaaca-cmdline-parser.h>
#include <ipaaca/ipaaca-string-utils.h>
// Global static library variables (run-time default configuration)
// Actual initial values are set in ipaaca.cc
/// Default payload type for new IUs (defaults to "JSON")
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_default_payload_type;
/// Default channel for buffers (defaults to "default")
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_default_channel;
/// Current console log level (defaults to warning), one of: IPAACA_LOG_LEVEL_CRITICAL, IPAACA_LOG_LEVEL_ERROR, IPAACA_LOG_LEVEL_WARNING, IPAACA_LOG_LEVEL_INFO, IPAACA_LOG_LEVEL_DEBUG, IPAACA_LOG_LEVEL_NONE
IPAACA_MEMBER_VAR_EXPORT extern unsigned int __ipaaca_static_option_log_level;
/// RSB host to connect to (defaults to "" = do not set, use global config)
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_rsb_host;
/// RSB port to connect to (defaults to "" = do not set, use global config)
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_rsb_port;
/// RSB transport to use (defaults to "" = do not set, use global config)
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_rsb_transport;
/// Whether to run in server mode on 'socket' transport (defaults to "" = do not set, use global config)
IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_rsb_socketserver;
IPAACA_MEMBER_VAR_EXPORT Lock& logger_lock();
#if _WIN32 || _WIN64
#define LOG_IPAACA_CONSOLE(msg) { ipaaca::Locker logging_locker(ipaaca::logger_lock()); std::time_t result = std::time(NULL); std::cout << "[LOG] " << std::asctime(std::localtime(&result)) << " : " << msg << std::endl; }
#else
// use normal gettimeofday() on POSIX
#define LOG_IPAACA_CONSOLE(msg) { ipaaca::Locker logging_locker(ipaaca::logger_lock()); timeval logging_tim; gettimeofday(&logging_tim, NULL); double logging_t1=logging_tim.tv_sec+(logging_tim.tv_usec/1000000.0); std::cout << "[LOG] " << std::setprecision(15) << logging_t1 << " : " << msg << std::endl; }
#endif
#if _WIN32 || _WIN64
#define IPAACA_SIMPLE_TIMER_BEGIN(N) ;
#define IPAACA_SIMPLE_TIMER_END(N, NAME) LOG_IPAACA_CONSOLE(NAME << " - time elapsed: Windows - IMPLEMENT ME")
#else
/// use IPAACA_SIMPLE_TIMER_BEGIN(mysymbol) to start time profiling at a line in code
/// Several blocks can be defined in the same stack frame if different symbols are chosen
#define IPAACA_SIMPLE_TIMER_BEGIN(N) struct timeval _ipaaca_timer_tvstart_ ## N; \
gettimeofday(&_ipaaca_timer_tvstart_ ## N, NULL);
/// use IPAACA_SIMPLE_TIMER_END(mysymbol, "message") to print time elapsed since correpsonding _BEGIN
#define IPAACA_SIMPLE_TIMER_END(N, NAME) struct timeval _ipaaca_timer_tvend_ ## N; \
gettimeofday(&_ipaaca_timer_tvend_ ## N, NULL); \
long _ipaaca_timer_usecs_ ## N = (_ipaaca_timer_tvend_ ## N.tv_sec*1000000 + _ipaaca_timer_tvend_ ## N.tv_usec) - (_ipaaca_timer_tvstart_ ## N.tv_sec*1000000 + _ipaaca_timer_tvstart_ ## N.tv_usec); \
LOG_IPAACA_CONSOLE(NAME << " - ̨́us elapsed: " << _ipaaca_timer_usecs_ ## N)
#endif
#include <ipaaca/ipaaca-config.h>
#include <ipaaca/ipaaca-converters.h>
#include <ipaaca/ipaaca-backend.h>
#include <ipaaca/ipaaca-payload.h>
#include <ipaaca/ipaaca-buffers.h>
#include <ipaaca/ipaaca-ius.h>
} // of namespace ipaaca
#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 util/notifier.h
*
* \brief Header file for component notification (i.e. module-level introspection).
*
* Include this file in addition to ipaaca.h to use the functionality.
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#ifndef __IPAACA_UTIL_NOTIFIER_H__
#define __IPAACA_UTIL_NOTIFIER_H__
#include <ipaaca/ipaaca.h>
#define _IPAACA_COMP_NOTIF_CATEGORY "componentNotify"
#define _IPAACA_COMP_NOTIF_NAME "name"
#define _IPAACA_COMP_NOTIF_FUNCTION "function"
#define _IPAACA_COMP_NOTIF_STATE "state"
#define _IPAACA_COMP_NOTIF_SEND_CATS "send_categories"
#define _IPAACA_COMP_NOTIF_RECV_CATS "recv_categories"
#define _IPAACA_COMP_NOTIF_STATE_NEW "new"
#define _IPAACA_COMP_NOTIF_STATE_OLD "old"
#define _IPAACA_COMP_NOTIF_STATE_DOWN "down"
namespace ipaaca {
namespace util {
class ComponentNotifier {
protected:
ComponentNotifier(const std::string& componentName, const std::string& componentFunction, const std::set<std::string>& sendCategories, const std::set<std::string>& receiveCategories);
ComponentNotifier(const std::string& componentName, const std::string& componentFunction, const std::set<std::string>& sendCategories, const std::set<std::string>& receiveCategories, ipaaca::OutputBuffer::ptr out_buf, ipaaca::InputBuffer::ptr in_buf);
public:
static std::shared_ptr<ComponentNotifier> create(const std::string& componentName, const std::string& componentFunction, const std::set<std::string>& sendCategories, const std::set<std::string>& receiveCategories);
static std::shared_ptr<ComponentNotifier> create(const std::string& componentName, const std::string& componentFunction, const std::set<std::string>& sendCategories, const std::set<std::string>& receiveCategories, ipaaca::OutputBuffer::ptr out_buf, ipaaca::InputBuffer::ptr in_buf);
public:
~ComponentNotifier();
protected:
void submit_notify(const std::string& current_state);
void handle_iu_event(ipaaca::IUInterface::ptr iu, ipaaca::IUEventType event_type, bool local);
public:
void add_notification_handler(ipaaca::IUEventHandlerFunction function);
void initialize();
void go_down();
protected:
ipaaca::OutputBuffer::ptr out_buf;
ipaaca::InputBuffer::ptr in_buf;
ipaaca::Lock lock;
bool initialized, gone_down;
std::vector<ipaaca::IUEventHandlerFunction> _handlers;
protected:
std::string name;
std::string function;
std::string state;
std::string send_categories;
std::string recv_categories;
public:
typedef std::shared_ptr<ComponentNotifier> ptr;
};
}} // of namespace ipaaca::util
#endif
Copyright (C) 2011 Milo Yip
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
--
This software and license copied in January 2015 from
https://github.com/miloyip/rapidjson/
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ALLOCATORS_H_
#define RAPIDJSON_ALLOCATORS_H_
#include "rapidjson.h"
#include "internal/meta.h"
#include <memory>
#if RAPIDJSON_HAS_CXX11
#include <type_traits>
#endif
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Allocator
/*! \class rapidjson::Allocator
\brief Concept for allocating, resizing and freeing memory block.
Note that Malloc() and Realloc() are non-static but Free() is static.
So if an allocator need to support Free(), it needs to put its pointer in
the header of memory block.
\code
concept Allocator {
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
// Allocate a memory block.
// \param size of the memory block in bytes.
// \returns pointer to the memory block.
void* Malloc(size_t size);
// Resize a memory block.
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
// \param newSize the new size in bytes.
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
// Free a memory block.
// \param pointer to the memory block. Null pointer is permitted.
static void Free(void *ptr);
};
\endcode
*/
/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
\ingroup RAPIDJSON_CONFIG
\brief User-defined kDefaultChunkCapacity definition.
User can define this as any \c size that is a power of 2.
*/
#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
#endif
///////////////////////////////////////////////////////////////////////////////
// CrtAllocator
//! C-runtime library allocator.
/*! This class is just wrapper for standard C library memory routines.
\note implements Allocator concept
*/
class CrtAllocator {
public:
static const bool kNeedFree = true;
void* Malloc(size_t size) {
if (size) // behavior of malloc(0) is implementation defined.
return RAPIDJSON_MALLOC(size);
else
return NULL; // standardize to returning NULL.
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
(void)originalSize;
if (newSize == 0) {
RAPIDJSON_FREE(originalPtr);
return NULL;
}
return RAPIDJSON_REALLOC(originalPtr, newSize);
}
static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }
bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
return true;
}
bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
return false;
}
};
///////////////////////////////////////////////////////////////////////////////
// MemoryPoolAllocator
//! Default memory allocator used by the parser and DOM.
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
It does not free memory blocks. And Realloc() only allocate new memory.
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
User may also supply a buffer as the first chunk.
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
The user-buffer is not deallocated by this allocator.
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
\note implements Allocator concept
*/
template <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator {
//! Chunk header for perpending to each chunk.
/*! Chunks are stored as a singly linked list.
*/
struct ChunkHeader {
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
size_t size; //!< Current size of allocated memory in bytes.
ChunkHeader *next; //!< Next chunk in the linked list.
};
struct SharedData {
ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
BaseAllocator* ownBaseAllocator; //!< base allocator created by this object.
size_t refcount;
bool ownBuffer;
};
static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData));
static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader));
static inline ChunkHeader *GetChunkHead(SharedData *shared)
{
return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
}
static inline uint8_t *GetChunkBuffer(SharedData *shared)
{
return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER;
}
static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
public:
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy
//! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
explicit
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunk_capacity_(chunkSize),
baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0))
{
RAPIDJSON_ASSERT(baseAllocator_ != 0);
RAPIDJSON_ASSERT(shared_ != 0);
if (baseAllocator) {
shared_->ownBaseAllocator = 0;
}
else {
shared_->ownBaseAllocator = baseAllocator_;
}
shared_->chunkHead = GetChunkHead(shared_);
shared_->chunkHead->capacity = 0;
shared_->chunkHead->size = 0;
shared_->chunkHead->next = 0;
shared_->ownBuffer = true;
shared_->refcount = 1;
}
//! Constructor with user-supplied buffer.
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
The user buffer will not be deallocated when this allocator is destructed.
\param buffer User supplied buffer.
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunk_capacity_(chunkSize),
baseAllocator_(baseAllocator),
shared_(static_cast<SharedData*>(AlignBuffer(buffer, size)))
{
RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER);
shared_->chunkHead = GetChunkHead(shared_);
shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER;
shared_->chunkHead->size = 0;
shared_->chunkHead->next = 0;
shared_->ownBaseAllocator = 0;
shared_->ownBuffer = false;
shared_->refcount = 1;
}
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT :
chunk_capacity_(rhs.chunk_capacity_),
baseAllocator_(rhs.baseAllocator_),
shared_(rhs.shared_)
{
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
++shared_->refcount;
}
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
++rhs.shared_->refcount;
this->~MemoryPoolAllocator();
baseAllocator_ = rhs.baseAllocator_;
chunk_capacity_ = rhs.chunk_capacity_;
shared_ = rhs.shared_;
return *this;
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT :
chunk_capacity_(rhs.chunk_capacity_),
baseAllocator_(rhs.baseAllocator_),
shared_(rhs.shared_)
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
rhs.shared_ = 0;
}
MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
this->~MemoryPoolAllocator();
baseAllocator_ = rhs.baseAllocator_;
chunk_capacity_ = rhs.chunk_capacity_;
shared_ = rhs.shared_;
rhs.shared_ = 0;
return *this;
}
#endif
//! Destructor.
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
*/
~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT {
if (!shared_) {
// do nothing if moved
return;
}
if (shared_->refcount > 1) {
--shared_->refcount;
return;
}
Clear();
BaseAllocator *a = shared_->ownBaseAllocator;
if (shared_->ownBuffer) {
baseAllocator_->Free(shared_);
}
RAPIDJSON_DELETE(a);
}
//! Deallocates all memory chunks, excluding the first/user one.
void Clear() RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
for (;;) {
ChunkHeader* c = shared_->chunkHead;
if (!c->next) {
break;
}
shared_->chunkHead = c->next;
baseAllocator_->Free(c);
}
shared_->chunkHead->size = 0;
}
//! Computes the total capacity of allocated memory chunks.
/*! \return total capacity in bytes.
*/
size_t Capacity() const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
size_t capacity = 0;
for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
capacity += c->capacity;
return capacity;
}
//! Computes the memory blocks allocated.
/*! \return total used bytes.
*/
size_t Size() const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
size_t size = 0;
for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
size += c->size;
return size;
}
//! Whether the allocator is shared.
/*! \return true or false.
*/
bool Shared() const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
return shared_->refcount > 1;
}
//! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
if (!size)
return NULL;
size = RAPIDJSON_ALIGN(size);
if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity))
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
return NULL;
void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size;
shared_->chunkHead->size += size;
return buffer;
}
//! Resizes a memory block (concept Allocator)
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
if (originalPtr == 0)
return Malloc(newSize);
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
if (newSize == 0)
return NULL;
originalSize = RAPIDJSON_ALIGN(originalSize);
newSize = RAPIDJSON_ALIGN(newSize);
// Do not shrink if new size is smaller than original
if (originalSize >= newSize)
return originalPtr;
// Simply expand it if it is the last allocation and there is sufficient space
if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) {
size_t increment = static_cast<size_t>(newSize - originalSize);
if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) {
shared_->chunkHead->size += increment;
return originalPtr;
}
}
// Realloc process: allocate and copy memory, do not free original buffer.
if (void* newBuffer = Malloc(newSize)) {
if (originalSize)
std::memcpy(newBuffer, originalPtr, originalSize);
return newBuffer;
}
else
return NULL;
}
//! Frees a memory block (concept Allocator)
static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing
//! Compare (equality) with another MemoryPoolAllocator
bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
return shared_ == rhs.shared_;
}
//! Compare (inequality) with another MemoryPoolAllocator
bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
return !operator==(rhs);
}
private:
//! Creates a new chunk.
/*! \param capacity Capacity of the chunk in bytes.
\return true if success.
*/
bool AddChunk(size_t capacity) {
if (!baseAllocator_)
shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
if (ChunkHeader* chunk = static_cast<ChunkHeader*>(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) {
chunk->capacity = capacity;
chunk->size = 0;
chunk->next = shared_->chunkHead;
shared_->chunkHead = chunk;
return true;
}
else
return false;
}
static inline void* AlignBuffer(void* buf, size_t &size)
{
RAPIDJSON_NOEXCEPT_ASSERT(buf != 0);
const uintptr_t mask = sizeof(void*) - 1;
const uintptr_t ubuf = reinterpret_cast<uintptr_t>(buf);
if (RAPIDJSON_UNLIKELY(ubuf & mask)) {
const uintptr_t abuf = (ubuf + mask) & ~mask;
RAPIDJSON_ASSERT(size >= abuf - ubuf);
buf = reinterpret_cast<void*>(abuf);
size -= abuf - ubuf;
}
return buf;
}
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
SharedData *shared_; //!< The shared data of the allocator
};
namespace internal {
template<typename, typename = void>
struct IsRefCounted :
public FalseType
{ };
template<typename T>
struct IsRefCounted<T, typename internal::EnableIfCond<T::kRefCounted>::Type> :
public TrueType
{ };
}
template<typename T, typename A>
inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n)
{
RAPIDJSON_NOEXCEPT_ASSERT(old_n <= SIZE_MAX / sizeof(T) && new_n <= SIZE_MAX / sizeof(T));
return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
}
template<typename T, typename A>
inline T *Malloc(A& a, size_t n = 1)
{
return Realloc<T, A>(a, NULL, 0, n);
}
template<typename T, typename A>
inline void Free(A& a, T *p, size_t n = 1)
{
static_cast<void>(Realloc<T, A>(a, p, n, 0));
}
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited
#endif
template <typename T, typename BaseAllocator = CrtAllocator>
class StdAllocator :
public std::allocator<T>
{
typedef std::allocator<T> allocator_type;
#if RAPIDJSON_HAS_CXX11
typedef std::allocator_traits<allocator_type> traits_type;
#else
typedef allocator_type traits_type;
#endif
public:
typedef BaseAllocator BaseAllocatorType;
StdAllocator() RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_()
{ }
StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
template<typename U>
StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(std::move(rhs)),
baseAllocator_(std::move(rhs.baseAllocator_))
{ }
#endif
#if RAPIDJSON_HAS_CXX11
using propagate_on_container_move_assignment = std::true_type;
using propagate_on_container_swap = std::true_type;
#endif
/* implicit */
StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_(allocator)
{ }
~StdAllocator() RAPIDJSON_NOEXCEPT
{ }
template<typename U>
struct rebind {
typedef StdAllocator<U, BaseAllocator> other;
};
typedef typename traits_type::size_type size_type;
typedef typename traits_type::difference_type difference_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::pointer pointer;
typedef typename traits_type::const_pointer const_pointer;
#if RAPIDJSON_HAS_CXX11
typedef typename std::add_lvalue_reference<value_type>::type &reference;
typedef typename std::add_lvalue_reference<typename std::add_const<value_type>::type>::type &const_reference;
pointer address(reference r) const RAPIDJSON_NOEXCEPT
{
return std::addressof(r);
}
const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
{
return std::addressof(r);
}
size_type max_size() const RAPIDJSON_NOEXCEPT
{
return traits_type::max_size(*this);
}
template <typename ...Args>
void construct(pointer p, Args&&... args)
{
traits_type::construct(*this, p, std::forward<Args>(args)...);
}
void destroy(pointer p)
{
traits_type::destroy(*this, p);
}
#else // !RAPIDJSON_HAS_CXX11
typedef typename allocator_type::reference reference;
typedef typename allocator_type::const_reference const_reference;
pointer address(reference r) const RAPIDJSON_NOEXCEPT
{
return allocator_type::address(r);
}
const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
{
return allocator_type::address(r);
}
size_type max_size() const RAPIDJSON_NOEXCEPT
{
return allocator_type::max_size();
}
void construct(pointer p, const_reference r)
{
allocator_type::construct(p, r);
}
void destroy(pointer p)
{
allocator_type::destroy(p);
}
#endif // !RAPIDJSON_HAS_CXX11
template <typename U>
U* allocate(size_type n = 1, const void* = 0)
{
return RAPIDJSON_NAMESPACE::Malloc<U>(baseAllocator_, n);
}
template <typename U>
void deallocate(U* p, size_type n = 1)
{
RAPIDJSON_NAMESPACE::Free<U>(baseAllocator_, p, n);
}
pointer allocate(size_type n = 1, const void* = 0)
{
return allocate<value_type>(n);
}
void deallocate(pointer p, size_type n = 1)
{
deallocate<value_type>(p, n);
}
#if RAPIDJSON_HAS_CXX11
using is_always_equal = std::is_empty<BaseAllocator>;
#endif
template<typename U>
bool operator==(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
{
return baseAllocator_ == rhs.baseAllocator_;
}
template<typename U>
bool operator!=(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
{
return !operator==(rhs);
}
//! rapidjson Allocator concept
static const bool kNeedFree = BaseAllocator::kNeedFree;
static const bool kRefCounted = internal::IsRefCounted<BaseAllocator>::Value;
void* Malloc(size_t size)
{
return baseAllocator_.Malloc(size);
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
{
return baseAllocator_.Realloc(originalPtr, originalSize, newSize);
}
static void Free(void *ptr) RAPIDJSON_NOEXCEPT
{
BaseAllocator::Free(ptr);
}
private:
template <typename, typename>
friend class StdAllocator; // access to StdAllocator<!T>.*
BaseAllocator baseAllocator_;
};
#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17
template <typename BaseAllocator>
class StdAllocator<void, BaseAllocator> :
public std::allocator<void>
{
typedef std::allocator<void> allocator_type;
public:
typedef BaseAllocator BaseAllocatorType;
StdAllocator() RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_()
{ }
StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
template<typename U>
StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
/* implicit */
StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_(baseAllocator)
{ }
~StdAllocator() RAPIDJSON_NOEXCEPT
{ }
template<typename U>
struct rebind {
typedef StdAllocator<U, BaseAllocator> other;
};
typedef typename allocator_type::value_type value_type;
private:
template <typename, typename>
friend class StdAllocator; // access to StdAllocator<!T>.*
BaseAllocator baseAllocator_;
};
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ENCODINGS_H_