From 6678618b85f7ef1dd8cfd6406016176ed89d3dbf Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 22 May 2013 06:19:20 -0400 Subject: [PATCH 001/185] Example corrected --- README | 6 ++++-- include/eixx/connect/basic_otp_mailbox.hpp | 11 ----------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/README b/README index 7362b5d..c5b3247 100644 --- a/README +++ b/README @@ -75,13 +75,15 @@ Here's an example use of the eixx library: while (dist_msg.reset(a_mbox.receive())) { std::cout << "Main mailbox got a distributed transport message:\n " - << *p << std::endl; + << *dist_msg << std::endl; - // Use the following pattern for a pattern match on the message. + // Compile the following pattern into the corresponding abstract tree. + // The expression must be a valid Erlang term static const eterm s_pattern = eterm::format("{From, {command, Cmd}}"); varbind binding; + // Pattern match the message and bind From and Cmd variables if (s_pattern.match(dist_msg->msg(), &binding)) { const eterm* cmd = binding->find("Cmd"); std::cout << "Got a command " << *cmd << std::endl; diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index 33b6389..d7e3cf9 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -215,17 +215,6 @@ class basic_otp_mailbox m_deadline_timer.cancel(); } - /** - * Get a message from mailbox that matches the given pattern. - * It will block until an apropiate message arrives. - * @param pattern ErlTerm with pattern to check - * @param binding VariableBinding to use. It can be 0. Default = 0 - * @return an pointer to the ErlTerm representing - * the body of the next message waiting in this mailbox. - * @exception EpiConnectionException if there was an connection error - */ - //bool receive(const eterm& a_pattern, varbind* a_binding = NULL); - /** * Block until response for a RPC call arrives. * @return a pointer to ErlTerm containing the response From c8ec7d4aced2da631e1c1423a9a8f4d9e1238e3f Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 2 Oct 2013 14:21:15 -0400 Subject: [PATCH 002/185] Work in progress --- .gitignore | 1 + include/eixx/marshal/am.hpp | 51 +++++++ include/eixx/marshal/atom.hpp | 171 ++-------------------- include/eixx/marshal/defaults.hpp | 18 +++ include/eixx/marshal/eterm.hpp | 33 ++--- include/eixx/marshal/eterm.ipp | 2 +- include/eixx/marshal/eterm_format.ipp | 94 ++++++++---- include/eixx/marshal/var.hpp | 98 ++++++++----- include/eixx/marshal/varbind.hpp | 28 ++-- include/eixx/marshal/visit_match.hpp | 2 +- include/eixx/marshal/visit_subst.hpp | 2 +- include/eixx/util/atom_table.hpp | 201 ++++++++++++++++++++++++++ src/Makefile.am | 3 +- src/am.cpp | 11 ++ src/atom.cpp | 6 +- src/defaults.cpp | 70 +++++++++ 16 files changed, 533 insertions(+), 258 deletions(-) create mode 100644 include/eixx/marshal/am.hpp create mode 100644 include/eixx/util/atom_table.hpp create mode 100644 src/am.cpp diff --git a/.gitignore b/.gitignore index 514756f..16ceb2f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.swp stamp-h1 eixx*.tar.gz aclocal.m4 diff --git a/include/eixx/marshal/am.hpp b/include/eixx/marshal/am.hpp new file mode 100644 index 0000000..3cc89e2 --- /dev/null +++ b/include/eixx/marshal/am.hpp @@ -0,0 +1,51 @@ +//---------------------------------------------------------------------------- +/// \file atom.hpp +//---------------------------------------------------------------------------- +/// \brief A class implementing an atom - enumerated string stored +/// stored in non-garbage collected hash table of fixed size. +//---------------------------------------------------------------------------- +// Copyright (c) 2010 Serge Aleynikov +// Created: 2010-09-20 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the eixx (Erlang C++ Interface) Library. + +Copyright (C) 2010 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ +#ifndef _EIXX_AM_HPP_ +#define _EIXX_AM_HPP_ + +#include + +namespace EIXX_NAMESPACE { + + using marshal::atom; + + // Constant global atom values + + extern atom am_true; + extern atom am_false; + extern atom am_undefined; + extern atom am_underscore; + +} // namespace EIXX_NAMESPACE + +#endif // _EIXX_AM_HPP_ diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 2b31854..dd051e5 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -41,6 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include #include namespace EIXX_NAMESPACE { @@ -59,151 +60,6 @@ namespace detail { } } - /// Non-garbage collected hash table for atoms. It stores strings - /// as atoms so that atoms can be quickly compared to with O(1) - /// complexity. The instance of this table is statically maintained - /// and its content is never cleared. The table contains a unique - /// list of strings represented as atoms added throughout the lifetime - /// of the application. - template - class atom_table { - public: - //typedef std::basic_string, Alloc> string_t; - typedef std::string string_t; - private: - // See http://www.azillionmonkeys.com/qed/hash.html - // Copyright 2004-2008 (c) by Paul Hsieh - struct hsieh_hash_fun { - static uint16_t get16bits(const char* d) { return *(const uint16_t *)d; } - - size_t operator()(const char* data) const { - int len = strlen(data); - uint32_t hash = len, tmp; - int rem; - - if (len <= 0 || data == NULL) return 0; - - rem = len & 3; - len >>= 2; - - /* Main loop */ - for (;len > 0; len--) { - hash += get16bits (data); - tmp = (get16bits (data+2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2*sizeof (uint16_t); - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) { - case 3: hash += get16bits (data); - hash ^= hash << 16; - hash ^= data[sizeof (uint16_t)] << 18; - hash += hash >> 11; - break; - case 2: hash += get16bits (data); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: hash += *data; - hash ^= hash << 10; - hash += hash >> 1; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; - } - }; - - static const size_t s_default_max_atoms = 1024*1024; - - int find_value(size_t bucket, const char* a_atom) { - typename char_int_hash_map::const_local_iterator - lit = m_index.begin(bucket), lend = m_index.end(bucket); - while(lit != lend && strcmp(a_atom, lit->first) != 0) ++lit; - return lit == lend ? -1 : lit->second; - } - public: - /// Returns the default atom table maximum size. The value can be - /// changed by setting the EI_ATOM_TABLE_SIZE environment variable. - static size_t default_size() { - const char* p = getenv("EI_ATOM_TABLE_SIZE"); - int n = p ? atoi(p) : s_default_max_atoms; - return n > 0 && n < 1024*1024*100 ? n : s_default_max_atoms; - } - - /// Returns the maximum number of atoms that can be stored in the atom table. - size_t capacity() const { return m_atoms.capacity(); } - - /// Returns the current number of atoms stored in the atom table. - size_t allocated() const { return m_atoms.size(); } - - explicit atom_table(size_t a_max_atoms = default_size()) - : m_index(a_max_atoms) { - m_atoms.reserve(a_max_atoms); - m_atoms.push_back(""); // The 0-th element is an empty atom (""). - m_index[""] = 0; - } - - ~atom_table() { - lock_guard guard(m_lock); - m_atoms.clear(); - m_index.clear(); - } - - /// Lookup an atom in the atom table by index. - const string_t& lookup(size_t n) const { return (*this)[n]; } - - /// Lookup an atom in the atom table by index. - const string_t& operator[] (size_t n) const { - BOOST_ASSERT(n < m_atoms.size()); - return m_atoms[n]; - } - - /// Lookup an atom in the atom table by name. If the atom is not - /// present in the atom table - add it. Return the index of the - /// atom in the atom table. - /// @throws std::runtime_error if atom table is full. - /// @throws err_bad_argument if atom size is longer than MAXATOMLEN - size_t lookup(const char* a_atom, size_t n) { return lookup(std::string(a_atom, n)); } - size_t lookup(const char* a_atom) { return lookup(std::string(a_atom)); } - size_t lookup(const std::string& a_atom) - throw(std::runtime_error, err_bad_argument) - { - if (a_atom.size() == 0) - return 0; - if (a_atom.size() > MAXATOMLEN) - throw err_bad_argument("Atom size is too long!"); - size_t bucket = m_index.bucket(a_atom.c_str()); - int n = find_value(bucket, a_atom.c_str()); - if (n >= 0) - return n; - - lock_guard guard(m_lock); - n = find_value(bucket, a_atom.c_str()); - if (n >= 0) - return n; - - n = m_atoms.size(); - if ((size_t)(n+1) == m_atoms.capacity()) - throw std::runtime_error("Atom hash table is full!"); - m_atoms.push_back(a_atom); - m_index[a_atom.c_str()] = n; - return n; - } - private: - std::vector m_atoms; - char_int_hash_map m_index; - Mutex m_lock; - }; } // namespace detail /** @@ -213,48 +69,43 @@ namespace detail { */ class atom { - size_t m_index; + int m_index; - typedef detail::atom_table<>::string_t string_t; + typedef util::atom_table<>::string_t string_t; public: - static detail::atom_table<>& atom_table(); + static util::atom_table<>& atom_table(); /// Create an empty atom atom() : m_index(0) { - BOOST_STATIC_ASSERT(sizeof(atom) == sizeof(void*)); + BOOST_STATIC_ASSERT(sizeof(atom) == 4); } /// Create an atom from the given string. /// @param atom the string to create the atom from. /// @throws std::runtime_error if atom table is full. /// @throws err_bad_argument if atom size is longer than MAXATOMLEN - atom(const char* s) - throw(std::runtime_error, err_bad_argument) + atom(const char* s) throw(std::runtime_error, err_bad_argument) : m_index(atom_table().lookup(string_t(s))) {} /// @copydoc atom::atom template - atom(const char (&s)[N]) - throw(std::runtime_error, err_bad_argument) + atom(const char (&s)[N]) throw(std::runtime_error, err_bad_argument) : m_index(atom_table().lookup(string_t(s, N))) {} /// @copydoc atom::atom - explicit atom(const std::string& s) - throw(std::runtime_error) + explicit atom(const std::string& s) throw(std::runtime_error) : m_index(atom_table().lookup(s)) {} /// @copydoc atom::atom template - explicit atom(const string& s) - throw(std::runtime_error) + explicit atom(const string& s) throw(std::runtime_error) : m_index(atom_table().lookup(string_t(s.c_str(), s.size()))) {} /// @copydoc atom::atom - atom(const char* s, size_t n) - throw(std::runtime_error) + atom(const char* s, size_t n) throw(std::runtime_error) : m_index(atom_table().lookup(string_t(s, n))) {} @@ -284,7 +135,7 @@ class atom bool empty() const { return m_index == 0; } /// Get atom's index in the atom table. - size_t index() const { return m_index; } + int index() const { return m_index; } void operator= (const atom& s) { m_index = s.m_index; } void operator= (const std::string& s) { m_index = atom_table().lookup(s); } diff --git a/include/eixx/marshal/defaults.hpp b/include/eixx/marshal/defaults.hpp index ab4e249..439fcff 100644 --- a/include/eixx/marshal/defaults.hpp +++ b/include/eixx/marshal/defaults.hpp @@ -45,6 +45,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # define likely(expr) (expr) #endif +#include + namespace EIXX_NAMESPACE { namespace marshal { @@ -89,6 +91,22 @@ namespace EIXX_NAMESPACE { /// Returns string representation of type \a a_type. const char* type_to_string(eterm_type a_type); + /// Converts \a a_type to string + /// @param a_type is the type to convert + /// @param a_prefix if true, the value is prepended with "::" + /// + /// Example: printf("%s\n", type_to_type_string(eterm_type::BOOL, true); + /// Outputs: ::bool() + const char* type_to_type_string(eterm_type a_type, bool a_prefix=false); + + /// Converts a string to eterm type + eterm_type type_string_to_type(const char* s, size_t n); + + /// Converts a string \a s to eterm type + inline eterm_type type_string_to_type(const char* s) { + return type_string_to_type(s, strlen(s)); + } + } // namespace EIXX_NAMESPACE #endif // _EIXX_DEFAULTS_HPP diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index bcae08c..c0ea29c 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -67,7 +67,7 @@ namespace { template struct enum_type, Alloc> { typedef epid type; }; template struct enum_type, Alloc> { typedef port type; }; template struct enum_type, Alloc> { typedef ref type; }; - template struct enum_type, Alloc> { typedef var type; }; + template struct enum_type { typedef var type; }; template struct enum_type, Alloc> { typedef tuple type; }; template struct enum_type, Alloc> { typedef list type; }; template struct enum_type, Alloc> { typedef trace type; }; @@ -174,7 +174,7 @@ class eterm { epid& get(const epid*) { check(PID); return vt; } port& get(const port*) { check(PORT); return vt; } ref& get(const ref*) { check(REF); return vt; } - var& get(const var*) { check(VAR); return vt; } + var& get(const var*) { check(VAR); return vt; } tuple& get(const tuple*) { check(TUPLE); return vt; } list& get(const list*) { check(LIST); return vt; } trace& get(const trace*) { check(TRACE); return vt; } @@ -198,13 +198,13 @@ class eterm { : m_type(STRING) { new (&vt.p) string(a, alloc); } eterm(const std::string& a, const Alloc& alloc = Alloc()) : m_type(STRING) { new (&vt.p) string(a.c_str(), a.size(), alloc); } - eterm(const atom& a) : m_type(ATOM) { new (&vt.p) atom(a); } + eterm(const atom& a) : m_type(ATOM) { new (&vt.p) atom(a); } eterm(const string& a) : m_type(STRING) { new (&vt.p) string(a);} eterm(const binary& a) : m_type(BINARY) { new (&vt.p) binary(a);} eterm(const epid& a) : m_type(PID) { new (&vt.p) epid(a); } eterm(const port& a) : m_type(PORT) { new (&vt.p) port(a); } eterm(const ref& a) : m_type(REF) { new (&vt.p) ref(a); } - eterm(const var& a) : m_type(VAR) { new (&vt.p) var(a); } + eterm(const var& a) : m_type(VAR) { new (&vt.p) var(a); } eterm(const tuple& a) : m_type(TUPLE) { new (&vt.p) tuple(a); } eterm(const list& a) : m_type(LIST) { new (&vt.p) list(a); } eterm(const trace& a) : m_type(TRACE) { new (&vt.p) trace(a); } @@ -241,16 +241,16 @@ class eterm { eterm(const eterm& a) : m_type(a.m_type) { BOOST_STATIC_ASSERT(sizeof(vartype) == sizeof(void*)); switch (m_type) { - case ATOM: { const atom& t = a.vt; new (&vt.p) atom(t); break; } - case STRING: { const string& t = a.vt; new (&vt.p) string(t); break; } - case BINARY: { const binary& t = a.vt; new (&vt.p) binary(t); break; } - case PID: { const epid& t = a.vt; new (&vt.p) epid(t); break; } - case PORT: { const port& t = a.vt; new (&vt.p) port(t); break; } - case REF: { const ref& t = a.vt; new (&vt.p) ref(t); break; } - case VAR: { const var& t = a.vt; new (&vt.p) var(t); break; } - case TUPLE: { const tuple& t = a.vt; new (&vt.p) tuple(t); break; } - case LIST: { const list& t = a.vt; new (&vt.p) list(t); break; } - case TRACE: { const trace& t = a.vt; new (&vt.p) trace(t); break; } + case ATOM: { const atom& t = a.vt; new (&vt.p) atom(t); break; } + case STRING: { const string& t = a.vt; new (&vt.p) string(t); break; } + case BINARY: { const binary& t = a.vt; new (&vt.p) binary(t); break; } + case PID: { const epid& t = a.vt; new (&vt.p) epid(t); break; } + case PORT: { const port& t = a.vt; new (&vt.p) port(t); break; } + case REF: { const ref& t = a.vt; new (&vt.p) ref(t); break; } + case VAR: { const var& t = a.vt; new (&vt.p) var(t); break; } + case TUPLE: { const tuple& t = a.vt; new (&vt.p) tuple(t); break; } + case LIST: { const list& t = a.vt; new (&vt.p) list(t); break; } + case TRACE: { const trace& t = a.vt; new (&vt.p) trace(t); break; } default: vt.i = a.vt.i; } @@ -270,7 +270,6 @@ class eterm { case PID: { epid& v = vt; v.~epid(); return; } case PORT: { port& v = vt; v.~port(); return; } case REF: { ref& v = vt; v.~ref(); return; } - case VAR: { var& v = vt; v.~var(); return; } case TUPLE: { tuple& v = vt; v.~tuple(); return; } case LIST: { list& v = vt; v.~list(); return; } case TRACE: { trace& v = vt; v.~trace(); return; } @@ -350,7 +349,7 @@ class eterm { const epid& to_pid() const { check(PID); return vt; } const port& to_port() const { check(PORT); return vt; } const ref& to_ref() const { check(REF); return vt; } - const var& to_var() const { check(VAR); return vt; } + const var& to_var() const { check(VAR); return vt; } const tuple& to_tuple() const { check(TUPLE); return vt; } tuple& to_tuple() { check(TUPLE); return vt; } const list& to_list() const { check(LIST); return vt; } @@ -498,7 +497,7 @@ class eterm { case PID: { const epid& t = vt; return wrapper(v, t); } case PORT: { const port& t = vt; return wrapper(v, t); } case REF: { const ref& t = vt; return wrapper(v, t); } - case VAR: { const var& t = vt; return wrapper(v, t); } + case VAR: { const var& t = vt; return wrapper(v, t); } case TUPLE: { const tuple& t = vt; return wrapper(v, t); } case LIST: { const list& t = vt; return wrapper(v, t); } case TRACE: { const trace& t = vt; return wrapper(v, t); } diff --git a/include/eixx/marshal/eterm.ipp b/include/eixx/marshal/eterm.ipp index 53f151d..e30a599 100644 --- a/include/eixx/marshal/eterm.ipp +++ b/include/eixx/marshal/eterm.ipp @@ -75,7 +75,7 @@ inline bool eterm::operator== (const eterm& rhs) const { case PID: { const epid& t = vt; return t == rhs.to_pid(); } case PORT: { const port& t = vt; return t == rhs.to_port(); } case REF: { const ref& t = vt; return t == rhs.to_ref(); } - case VAR: { const var& t = vt; return t == rhs.to_var(); } + case VAR: { const var& t = vt; return t == rhs.to_var(); } case TUPLE: { const tuple& t = vt; return t == rhs.to_tuple(); } case LIST: { const list& t = vt; return t == rhs.to_list(); } case TRACE: { const trace& t = vt; return t == rhs.to_trace(); } diff --git a/include/eixx/marshal/eterm_format.ipp b/include/eixx/marshal/eterm_format.ipp index 8281216..a130b0a 100644 --- a/include/eixx/marshal/eterm_format.ipp +++ b/include/eixx/marshal/eterm_format.ipp @@ -68,31 +68,59 @@ namespace marshal { , ERL_MAX_NAME_LENGTH = 255 /* Max length of variable names */ }; - static void skip_null_chars(const char** fmt) { - for(char c = **fmt; c == ' ' || c == '\t' || c == '\n'; c = *(++(*fmt))); + static void skip_ws_and_comments(const char** fmt) { + bool inside_comment = false; + for(char c = **fmt; c; c = *(++(*fmt))) { + if (inside_comment) { + if (c == '\n') inside_comment = false; + continue; + } else if (c == ' ' || c == '\t' || c == '\n' || c == '\r') { + continue; + } else if (c == '%') { + inside_comment = true; + continue; + } + break; + } } - static char *pvariable(const char **fmt, char *buf) + static var pvariable(const char **fmt) { - const char* start = *fmt; + const char* start = *fmt, *p = start; char c; int len; - skip_null_chars(fmt); + skip_ws_and_comments(fmt); - while (1) { - c = *(*fmt)++; - if (isalnum((int) c) || (c == '_')) - continue; - else - break; - } - (*fmt)--; - len = *fmt - start; - memcpy(buf, start, len); - buf[len] = 0; + for (c = *p; c && (isalnum((int)c) || (c == '_')); c = *(++p)); - return buf; + const char* end = p; + + eterm_type type; + + // TODO: Add recursive type checking + // (i.e. A :: [{atom(), [integer() | string() | double() | tuple()]}]) + if (c == ':' && *(p+1) == ':') { + p += 2; + + const char* tps = p; + + for (c = *p; c && isalnum((int)c); c = *(++p)); + + if (c == '(' && *(p+1) == ')') { + type = type_string_to_type(tps, p - tps); + if (t == eterm_type::UNDEFINED) + throw err_format_exception("Error parsing variable type", start); + p += 2; + } else + throw err_format_exception("Invalid variable type", tps); + } else + type = eterm_type::UNDEFINED; + + *fmt = p; + len = end - start; + + return var(start, len, type); } /* pvariable */ @@ -102,7 +130,7 @@ namespace marshal { char c; int len; - skip_null_chars(fmt); + skip_ws_and_comments(fmt); while (1) { c = *(*fmt)++; @@ -128,7 +156,7 @@ namespace marshal { char c; int len,dotp=0; - skip_null_chars(fmt); + skip_ws_and_comments(fmt); while (1) { c = *(*fmt)++; @@ -156,7 +184,7 @@ namespace marshal { char c; int len; - // skip_null_chars(fmt); + // skip_ws_and_comments(fmt); while (1) { c = *(*fmt)++; @@ -182,7 +210,7 @@ namespace marshal { char c; int len; - skip_null_chars(fmt); + skip_ws_and_comments(fmt); while (1) { c = *(*fmt)++; @@ -222,7 +250,7 @@ namespace marshal { int rc=ERL_OK; /* this next section hacked to remove the va_arg calls */ - skip_null_chars(fmt); + skip_ws_and_comments(fmt); switch (*(*fmt)++) { case 'w': @@ -268,7 +296,7 @@ namespace marshal { { int res=ERL_FMT_ERR; - skip_null_chars(fmt); + skip_ws_and_comments(fmt); switch (*(*fmt)++) { @@ -310,7 +338,7 @@ namespace marshal { { int res=ERL_FMT_ERR; - skip_null_chars(fmt); + skip_ws_and_comments(fmt); switch (*(*fmt)++) { @@ -323,12 +351,11 @@ namespace marshal { break; case '|': - skip_null_chars(fmt); + skip_ws_and_comments(fmt); if (isupper((int)**fmt) || (**fmt == '_')) { - char wbuf[BUFSIZ]; - char* s = pvariable(fmt, wbuf); - v.push_back( eterm(var(s, a_alloc)) ); - skip_null_chars(fmt); + var a = pvariable(fmt, wbuf); + v.push_back(eterm(a)); + skip_ws_and_comments(fmt); if (**fmt == ']') res = ERL_OK; break; @@ -359,7 +386,7 @@ namespace marshal { Alloc alloc(a_alloc); eterm ret; - skip_null_chars(fmt); + skip_ws_and_comments(fmt); switch (*(*fmt)++) { case '{': @@ -397,8 +424,8 @@ namespace marshal { char* a = patom(fmt, wbuf); ret.set( eterm(atom(a)) ); } else if (isupper((int)**fmt) || (**fmt == '_')) { - char* v = pvariable(fmt, wbuf); - ret.set( eterm(var(v, alloc)) ); + var v = pvariable(fmt, wbuf); + ret.set( eterm(var) ); } else if (isdigit((int)**fmt) || **fmt == '-') { /* integer/float ? */ char* digit = pdigit(fmt, wbuf); if (strchr(digit,(int) '.') == NULL) @@ -416,6 +443,9 @@ namespace marshal { break; } + if (ret.empty()) + throw err_format_exception("invalid term", *fmt); + return ret; } /* eformat */ diff --git a/include/eixx/marshal/var.hpp b/include/eixx/marshal/var.hpp index 8ec7e60..5e77aea 100644 --- a/include/eixx/marshal/var.hpp +++ b/include/eixx/marshal/var.hpp @@ -48,26 +48,53 @@ namespace marshal { * If you use '_' as variable, it will allways succeeds in matching, but * it will not be bound. **/ -template -class var : protected string +class var { - typedef string base_t; -public: - var(const Alloc& a = Alloc()) : base_t("_", a) {} - var(const char* s, const Alloc& a = Alloc()) : base_t(s, a) {} - var(const std::string& s, const Alloc& a = Alloc()) : base_t(s.c_str(), s.size(), a) {} - var(const char* s, size_t n, const Alloc& a = Alloc()) : base_t(s, n, a) {} - var(const var& s) : base_t(s) {} + union u { + struct s { + uint32_t type; + atom name; + } s; + uint64_t i; + + } m_data; - const char* c_str() const { return base_t::c_str(); } - const string& name() const { return *this; } - size_t size() const { return base_t::size(); } - size_t length() const { return base_t::length(); } + BOOST_STATIC_ASSERT(sizeof(var) == 8); - bool is_any() const { return base_t::size() == 1 && c_str()[0] == '_'; } + bool check_type(eterm_type t) const { return is_any() || t == type(); } + +public: + var(eterm_type t = eterm_type::UNDEFINED) + { m_data.s.type = t; m_data.s.name = am_ANY_; } + var(const char* s, eterm_type t = eterm_type::UNDEFINED) + { m_data.s.type = t; m_data.s.name = atom(s); } + var(const std::string& s, eterm_type t = eterm_type::UNDEFINED) + { m_data.s.type = t; m_data.s.name = atom(s); } + template + var(const std::string& s, eterm_type t = eterm_type::UNDEFINED) + { m_data.s.type = t; m_data.s.name = atom(s); } + var(const char* s, size_t n, eterm_type t = eterm_type::UNDEFINED) + { m_data.s.type = t; m_data.s.name = atom(s, n); } + var(const atom& s, eterm_type t = eterm_type::UNDEFINED) + { m_data.s.type = t; m_data.s.name = s; } + var(const var& v) { m_data.i = v.m_data.i; } + + const char* c_str() const { return m_data.s.name.c_str(); } + const string_t& str() const { return m_data.s.name.to_string(); } + atom name() const { return m_data.s.name; } + size_t length() const { return m_data.s.name.length(); } + + eterm_type type() const { return m_data.s.type; } + bool is_any() const { return name() == am_ANY_; } + + const string_t& to_string() const { + std::stringstream s; + s << name().to_string() << type_to_type_string(type(), true); + return s.str(); + } template - bool operator==(const T&) const { return false; } + bool operator==(const T&) const { return false; } size_t encode_size() const { throw err_encode_exception("Cannot encode vars!"); } @@ -75,39 +102,44 @@ class var : protected string throw err_encode_exception("Cannot encode vars!"); } + template const eterm* find_unbound(const varbind* binding = NULL) const { - if (is_any()) return NULL; - return binding ? binding->find(c_str()) : NULL; + return binding ? binding->find(name()) : NULL; } + template bool subst(eterm& out, const varbind* binding) const - throw (err_unbound_variable) { - if (is_any()) throw err_unbound_variable(c_str()); - const eterm* term = binding ? binding->find(c_str()) : NULL; - if (!term) throw err_unbound_variable(c_str()); + throw (err_unbound_variable) + { + const eterm* term = binding ? binding->find(name()) : NULL; + if (!term || !check_type(term->type())) + throw err_unbound_variable(c_str()); out = *term; return true; } + template bool match(const eterm& pattern, varbind* binding) const - throw (err_unbound_variable) { - if (is_any()) return true; - const eterm* value = binding ? binding->find(c_str()) : NULL; + throw (err_unbound_variable) + { + if (!binding) return false; + const eterm* value = binding ? binding->find(name()) : NULL; if (value) - return value->match(pattern, binding); - if (binding != NULL) { - // Bind the variable - eterm et; - binding->bind(name(), pattern.subst(et, binding) ? et : pattern); - } + return check_type(value->type()) ? value->match(pattern, binding) : false; + if (!check_type(pattern.type())) + return false; + // Bind the variable + eterm et; + binding->bind(name(), pattern.subst(et, binding) ? et : pattern); return true; } + template std::ostream& dump(std::ostream& out, const varbind* binding = NULL) const { - if (is_any()) { return out << c_str(); } const eterm* term = binding ? binding->find(name()) : NULL; - return out << (term ? term->to_string(std::string::npos, binding) : *this); + return out << (term && check_type(term->type()) + ? term->to_string(std::string::npos, binding) : *this); } }; @@ -116,7 +148,7 @@ class var : protected string namespace std { template - ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::var& s) { + ostream& operator<< (ostream& out, EIXX_NAMESPACE::marshal::var s) { return s.dump(out); } } // namespace std diff --git a/include/eixx/marshal/varbind.hpp b/include/eixx/marshal/varbind.hpp index 8c789b2..341a218 100644 --- a/include/eixx/marshal/varbind.hpp +++ b/include/eixx/marshal/varbind.hpp @@ -52,9 +52,7 @@ class varbind { std::ostream& out, const varbind& binding); protected: - typedef std::map< - string, eterm, std::less< string >, Alloc - > eterm_map_t; + typedef std::map, std::less, Alloc> eterm_map_t; public: explicit varbind(const Alloc& a_alloc = Alloc()) @@ -73,12 +71,16 @@ class varbind { * @param a_term eterm to bind (must be non-zero). */ void bind(const char* a_var_name, const eterm& a_term) { - bind(string(a_var_name), a_term); + bind(atom(a_var_name), a_term); } void bind(const string& a_var_name, const eterm& a_term) { + bind(atom(a_var_name), a_term); + } + + void bind(atom a_var_name, const eterm& a_term) { // bind only if is unbound - m_term_map.insert(std::pair, eterm >(a_var_name, a_term)); + m_term_map.insert(std::make_pair(a_var_name, a_term)); } /** @@ -87,21 +89,29 @@ class varbind { * @return bound eterm pointer if variable is bound, 0 otherwise */ const eterm* - find(const char* a_var_name) const { return find(string(a_var_name)); } + find(const char* a_var_name) const { return find(atom(a_var_name)); } + + const eterm* + find(const string& a_var_name) const { return find(atom(a_var_name)); } const eterm* - find(const string& a_var_name) const { + find(atom a_var_name) const { typename eterm_map_t::const_iterator p = m_term_map.find(a_var_name); return (p != m_term_map.end()) ? &p->second : NULL; } const eterm* operator[] (const char* a_var_name) const throw(err_unbound_variable) { - return (*this)[string(a_var_name)]; + return (*this)[atom(a_var_name)]; } const eterm* operator[] (const string& a_var_name) const throw(err_unbound_variable) { + return (*this)[atom(a_var_name)]; + } + + const eterm* + operator[] (atom a_var_name) const throw(err_unbound_variable) { const eterm* p = find(a_var_name); if (!p) throw err_unbound_variable(a_var_name.c_str()); return p; @@ -148,7 +158,7 @@ namespace std { for (typename varbind::eterm_map_t::const_iterator it = binding.m_term_map.begin(); it != binding.m_term_map.end(); ++it) - out << " " << it->first << " = " << it->second << std::endl; + out << " " << it->first.to_string() << " = " << it->second << std::endl; return out; } diff --git a/include/eixx/marshal/visit_match.hpp b/include/eixx/marshal/visit_match.hpp index 92e1e63..a218ee6 100644 --- a/include/eixx/marshal/visit_match.hpp +++ b/include/eixx/marshal/visit_match.hpp @@ -53,7 +53,7 @@ class visit_eterm_match bool operator()(const tuple& a) const { return a.match(m_pattern, m_binding); } bool operator()(const list& a) const { return a.match(m_pattern, m_binding); } - bool operator()(const var& a) const { return a.match(m_pattern, m_binding); } + bool operator()(const var& a) const { return a.match(m_pattern, m_binding); } template bool operator()(const T& a) const { diff --git a/include/eixx/marshal/visit_subst.hpp b/include/eixx/marshal/visit_subst.hpp index 5d6eacd..86b6f1d 100644 --- a/include/eixx/marshal/visit_subst.hpp +++ b/include/eixx/marshal/visit_subst.hpp @@ -53,7 +53,7 @@ class visit_eterm_subst bool operator()(const tuple& a) const { return a.subst(m_out, m_binding); } bool operator()(const list& a) const { return a.subst(m_out, m_binding); } - bool operator()(const var& a) const { return a.subst(m_out, m_binding); } + bool operator()(const var& a) const { return a.subst(m_out, m_binding); } template bool operator()(const T& a) const { return false; } diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp new file mode 100644 index 0000000..73b0a1b --- /dev/null +++ b/include/eixx/util/atom_table.hpp @@ -0,0 +1,201 @@ +//---------------------------------------------------------------------------- +/// \file atom.hpp +//---------------------------------------------------------------------------- +/// \brief A class implementing an atom - enumerated string stored +/// stored in non-garbage collected hash table of fixed size. +//---------------------------------------------------------------------------- +// Copyright (c) 2010 Serge Aleynikov +// Created: 2010-09-20 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the eixx (Erlang C++ Interface) Library. + +Copyright (C) 2010 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ +#ifndef _EIXX_ATOM_TABLE_HPP_ +#define _EIXX_ATOM_TABLE_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace EIXX_NAMESPACE { +namespace util { + + namespace eid = EIXX_NAMESPACE::detail; + using eid::lock_guard; + + /// Non-garbage collected hash table for atoms. It stores strings + /// as atoms so that atoms can be quickly compared to with O(1) + /// complexity. The instance of this table is statically maintained + /// and its content is never cleared. The table contains a unique + /// list of strings represented as atoms added throughout the lifetime + /// of the application. + template + class atom_table { + public: + //typedef std::basic_string, Alloc> string_t; + typedef std::string string_t; + private: + // See http://www.azillionmonkeys.com/qed/hash.html + // Copyright 2004-2008 (c) by Paul Hsieh + struct hsieh_hash_fun { + static uint16_t get16bits(const char* d) { return *(const uint16_t *)d; } + + int operator()(const char* data) const { + int len = strlen(data); + uint32_t hash = len, tmp; + int rem; + + if (len <= 0 || data == NULL) return 0; + + rem = len & 3; + len >>= 2; + + /* Main loop */ + for (;len > 0; len--) { + hash += get16bits (data); + tmp = (get16bits (data+2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2*sizeof (uint16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) { + case 3: hash += get16bits (data); + hash ^= hash << 16; + hash ^= data[sizeof (uint16_t)] << 18; + hash += hash >> 11; + break; + case 2: hash += get16bits (data); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: hash += *data; + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; + } + }; + + static const int s_default_max_atoms = 1024*1024; + + int find_value(size_t bucket, const char* a_atom) { + typename char_int_hash_map::const_local_iterator + lit = m_index.begin(bucket), lend = m_index.end(bucket); + while(lit != lend && strcmp(a_atom, lit->first) != 0) ++lit; + return lit == lend ? -1 : lit->second; + } + public: + /// Returns the default atom table maximum size. The value can be + /// changed by setting the EI_ATOM_TABLE_SIZE environment variable. + static size_t default_size() { + const char* p = getenv("EI_ATOM_TABLE_SIZE"); + int n = p ? atoi(p) : s_default_max_atoms; + return n > 0 && n < 1024*1024*100 ? n : s_default_max_atoms; + } + + /// Returns the maximum number of atoms that can be stored in the atom table. + size_t capacity() const { return m_atoms.capacity(); } + + /// Returns the current number of atoms stored in the atom table. + size_t allocated() const { return m_atoms.size(); } + + explicit atom_table(int a_max_atoms = default_size()) + : m_index(a_max_atoms) { + m_atoms.reserve(a_max_atoms); + m_atoms.push_back(""); // The 0-th element is an empty atom (""). + m_index[""] = 0; + } + + ~atom_table() { + lock_guard guard(m_lock); + m_atoms.clear(); + m_index.clear(); + } + + /// Lookup an atom in the atom table by index. + const string_t& lookup(size_t n) const { return (*this)[n]; } + + /// Lookup an atom in the atom table by index. + const string_t& operator[] (int n) const { + BOOST_ASSERT((size_t)n < m_atoms.size()); + return m_atoms[n]; + } + + /// Lookup an atom in the atom table by name. If the atom is not + /// present in the atom table - add it. Return the index of the + /// atom in the atom table. + /// @throws std::runtime_error if atom table is full. + /// @throws err_bad_argument if atom size is longer than MAXATOMLEN + int lookup(const char* a_atom, size_t n) { return lookup(std::string(a_atom, n)); } + int lookup(const char* a_atom) { return lookup(std::string(a_atom)); } + int lookup(const std::string& a_atom) + throw(std::runtime_error, err_bad_argument) + { + if (a_atom.size() == 0) + return 0; + if (a_atom.size() > MAXATOMLEN) + throw err_bad_argument("Atom size is too long!"); + size_t bucket = m_index.bucket(a_atom.c_str()); + int n = find_value(bucket, a_atom.c_str()); + if (n >= 0) + return n; + + lock_guard guard(m_lock); + n = find_value(bucket, a_atom.c_str()); + if (n >= 0) + return n; + + n = m_atoms.size(); + if ((size_t)(n+1) == m_atoms.capacity()) + throw std::runtime_error("Atom hash table is full!"); + m_atoms.push_back(a_atom); + m_index[a_atom.c_str()] = n; + return n; + } + private: + std::vector m_atoms; + char_int_hash_map m_index; + Mutex m_lock; + }; + +} // namespace util +} // namespace EIXX_NAMESPACE + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 1b0718f..4fdeb19 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,6 +25,7 @@ eixx_hdrs2 = connect/basic_otp_connection.hpp \ connect/transport_otp_connection_uds.hpp \ connect/verbose.hpp eixx_hdrs3 = marshal/alloc_base.hpp \ + marshal/am.hpp \ marshal/atom.hpp \ marshal/binary.hpp \ marshal/binary.ipp \ @@ -75,7 +76,7 @@ libeixx_la_hdr3_HEADERS = $(eixx_hdrs3:%=../include/@PACKAGE@/%) libeixx_la_hdr4dir = $(includedir)/@PACKAGE@/util libeixx_la_hdr4_HEADERS = $(eixx_hdrs4:%=../include/@PACKAGE@/%) -libeixx_la_SOURCES = atom.cpp defaults.cpp basic_otp_node_local.cpp \ +libeixx_la_SOURCES = am.cpp atom.cpp defaults.cpp basic_otp_node_local.cpp \ $(eixx_headers:%=../include/@PACKAGE@/%) libeixx_la_LTADD = -version-info 0:1 -shared libeixx_la_LIBS = $(BOOST_THREAD_LIB) $(CRYPTO_LIBS) diff --git a/src/am.cpp b/src/am.cpp new file mode 100644 index 0000000..da18975 --- /dev/null +++ b/src/am.cpp @@ -0,0 +1,11 @@ +#include + +namespace EIXX_NAMESPACE { + + atom am_ANY_ = atom("_"); + atom am_true = atom("true"); + atom am_false = atom("false"); + atom am_undefined = atom("undefined"); + +} // namespace EIXX_NAMESPACE + diff --git a/src/atom.cpp b/src/atom.cpp index 5c09439..2faae71 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -3,11 +3,11 @@ //#include namespace EIXX_NAMESPACE { -namespace marshal { +namespace util { - detail::atom_table<>& atom::atom_table() { + util::atom_table<>& atom::atom_table() { //return boost::details::pool::singleton_default >::instance(); - static detail::atom_table<> s_atom_table; + static util::atom_table<> s_atom_table; return s_atom_table; } diff --git a/src/defaults.cpp b/src/defaults.cpp index 2f88050..f4d1855 100644 --- a/src/defaults.cpp +++ b/src/defaults.cpp @@ -21,5 +21,75 @@ namespace EIXX_NAMESPACE { } } + const char* type_to_type_string(eterm_type a_type, bool a_prefix) { + switch (a_type) { + case LONG : return a_prefix ? "::int()" : "int()"; + case DOUBLE: return a_prefix ? "::float()" : "float()"; + case BOOL : return a_prefix ? "::bool()" : "bool()"; + case ATOM : return a_prefix ? "::atom()" : "atom()"; + case STRING: return a_prefix ? "::string()" : "string()"; + case BINARY: return a_prefix ? "::binary()" : "binary()"; + case PID : return a_prefix ? "::pid()" : "pid()"; + case PORT : return a_prefix ? "::port()" : "port()"; + case REF : return a_prefix ? "::ref()" : "ref()"; + case VAR : return a_prefix ? "::var()" : "var()"; + case TUPLE : return a_prefix ? "::tuple()" : "tuple()"; + case LIST : return a_prefix ? "::list()" : "list()"; + case TRACE : return a_prefix ? "::trace()" : "trace()"; + default : return ""; + } + } + + eterm_type type_string_to_type(const char* s, size_t n) { + eterm_type r = eterm_type::UNDEFINED; + + if (n < 3) return r; + + int m = n - 1; + const char* p = s+1; + + switch (s[0]) { + case 'i': + if (strncmp(p,"nt",m) == 0) r = eterm_type::LONG; + break; + case 'd': + if (strncmp(p,"ouble",m) == 0) r = eterm_type::DOUBLE; + break; + case 'f': + if (strncmp(p,"loat",m) == 0) r = eterm_type::DOUBLE; + break; + case 'b': + if (strncmp(p,"ool",m) == 0) r = eterm_type::BOOL; + else if (strncmp(p,"inary",m) == 0) r = eterm_type::BINARY; + break; + case 'a': + if (strncmp(p,"tom",m) == 0) r = eterm_type::ATOM; + break; + case 's': + if (strncmp(p,"tring",m) == 0) r = eterm_type::STRING; + break; + case 'p': + if (strncmp(p,"id",m) == 0) r = eterm_type::PID; + else if (strncmp(p,"ort",m) == 0) r = eterm_type::PORT; + break; + case 'r': + if (strncmp(p,"ef",m) == 0) r = eterm_type::REF; + break; + case 'v': + if (strncmp(p,"ar",m) == 0) r = eterm_type::VAR; + break; + case 't': + if (strncmp(p,"uple",m) == 0) r = eterm_type::TUPLE; + else if (strncmp(p,"race",m) == 0) r = eterm_type::TRACE; + break; + case 'l': + if (strncmp(p,"ist",m) == 0) r = eterm_type::LIST; + break; + default: + break; + } + return r; + } + } // namespace EIXX_NAMESPACE From 39bd4d263da9a8edbd9440a16b62dae45a0ca956 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 2 Oct 2013 14:23:37 -0400 Subject: [PATCH 003/185] Docs changed --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index c5b3247..5885cb2 100644 --- a/README +++ b/README @@ -84,7 +84,7 @@ Here's an example use of the eixx library: varbind binding; // Pattern match the message and bind From and Cmd variables - if (s_pattern.match(dist_msg->msg(), &binding)) { + if (dist_msg->msg().match(s_pattern, &binding)) { const eterm* cmd = binding->find("Cmd"); std::cout << "Got a command " << *cmd << std::endl; // Process command, e.g.: From aa776552e40d9fc4be0ae885b5a3a76f37d17b7d Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 2 Oct 2013 15:37:45 -0400 Subject: [PATCH 004/185] Work in progress --- include/eixx/eterm.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index 4bd1930..5c24dd1 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -47,7 +47,7 @@ typedef marshal::ref ref; typedef marshal::tuple tuple; typedef marshal::list list; typedef marshal::trace trace; -typedef marshal::var var; +typedef marshal::var var; typedef marshal::varbind varbind; typedef marshal::eterm_pattern_matcher eterm_pattern_matcher; typedef marshal::eterm_pattern_action eterm_pattern_action; From 6c9318988636b252f4ed12c97b8a37770fa07af6 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 2 Oct 2013 17:42:19 -0400 Subject: [PATCH 005/185] Work in progress --- include/eixx/eterm.hpp | 2 +- include/eixx/marshal/am.hpp | 8 +-- include/eixx/marshal/eterm.hpp | 2 +- include/eixx/marshal/eterm_format.ipp | 10 ++-- include/eixx/marshal/var.hpp | 70 +++++++++++------------- include/eixx/marshal/varbind.hpp | 2 +- include/eixx/marshal/visit.hpp | 2 +- include/eixx/marshal/visit_subst.hpp | 2 +- include/eixx/util/async_wait_timeout.hpp | 2 +- src/am.cpp | 8 +-- src/atom.cpp | 4 +- src/defaults.cpp | 30 +++++----- 12 files changed, 68 insertions(+), 74 deletions(-) diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index 5c24dd1..65a5076 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -54,7 +54,7 @@ typedef marshal::eterm_pattern_action eterm_pattern_action; namespace detail { BOOST_STATIC_ASSERT(sizeof(eterm) == 2*sizeof(void*)); - BOOST_STATIC_ASSERT(sizeof(atom) == sizeof(void*)); + BOOST_STATIC_ASSERT(sizeof(atom) == sizeof(int)); BOOST_STATIC_ASSERT(sizeof(string) == sizeof(void*)); BOOST_STATIC_ASSERT(sizeof(binary) == sizeof(void*)); BOOST_STATIC_ASSERT(sizeof(epid) == sizeof(void*)); diff --git a/include/eixx/marshal/am.hpp b/include/eixx/marshal/am.hpp index 3cc89e2..9a7c7a0 100644 --- a/include/eixx/marshal/am.hpp +++ b/include/eixx/marshal/am.hpp @@ -41,10 +41,10 @@ namespace EIXX_NAMESPACE { // Constant global atom values - extern atom am_true; - extern atom am_false; - extern atom am_undefined; - extern atom am_underscore; + extern const atom am_ANY_; + extern const atom am_true; + extern const atom am_false; + extern const atom am_undefined; } // namespace EIXX_NAMESPACE diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index c0ea29c..c82b9f4 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -67,7 +67,7 @@ namespace { template struct enum_type, Alloc> { typedef epid type; }; template struct enum_type, Alloc> { typedef port type; }; template struct enum_type, Alloc> { typedef ref type; }; - template struct enum_type { typedef var type; }; + template struct enum_type { typedef var type; }; template struct enum_type, Alloc> { typedef tuple type; }; template struct enum_type, Alloc> { typedef list type; }; template struct enum_type, Alloc> { typedef trace type; }; diff --git a/include/eixx/marshal/eterm_format.ipp b/include/eixx/marshal/eterm_format.ipp index a130b0a..1e515d6 100644 --- a/include/eixx/marshal/eterm_format.ipp +++ b/include/eixx/marshal/eterm_format.ipp @@ -109,13 +109,13 @@ namespace marshal { if (c == '(' && *(p+1) == ')') { type = type_string_to_type(tps, p - tps); - if (t == eterm_type::UNDEFINED) + if (type == UNDEFINED) throw err_format_exception("Error parsing variable type", start); p += 2; } else throw err_format_exception("Invalid variable type", tps); } else - type = eterm_type::UNDEFINED; + type = UNDEFINED; *fmt = p; len = end - start; @@ -353,7 +353,7 @@ namespace marshal { case '|': skip_ws_and_comments(fmt); if (isupper((int)**fmt) || (**fmt == '_')) { - var a = pvariable(fmt, wbuf); + var a = pvariable(fmt); v.push_back(eterm(a)); skip_ws_and_comments(fmt); if (**fmt == ']') @@ -424,8 +424,8 @@ namespace marshal { char* a = patom(fmt, wbuf); ret.set( eterm(atom(a)) ); } else if (isupper((int)**fmt) || (**fmt == '_')) { - var v = pvariable(fmt, wbuf); - ret.set( eterm(var) ); + var v = pvariable(fmt); + ret.set( eterm(v) ); } else if (isdigit((int)**fmt) || **fmt == '-') { /* integer/float ? */ char* digit = pdigit(fmt, wbuf); if (strchr(digit,(int) '.') == NULL) diff --git a/include/eixx/marshal/var.hpp b/include/eixx/marshal/var.hpp index 5e77aea..e33a91f 100644 --- a/include/eixx/marshal/var.hpp +++ b/include/eixx/marshal/var.hpp @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include +#include #include namespace EIXX_NAMESPACE { @@ -50,44 +51,37 @@ namespace marshal { **/ class var { - union u { - struct s { - uint32_t type; - atom name; - } s; - uint64_t i; - - } m_data; - - BOOST_STATIC_ASSERT(sizeof(var) == 8); + uint32_t m_type; + atom m_name; bool check_type(eterm_type t) const { return is_any() || t == type(); } + typedef util::atom_table<>::string_t string_t; public: - var(eterm_type t = eterm_type::UNDEFINED) - { m_data.s.type = t; m_data.s.name = am_ANY_; } - var(const char* s, eterm_type t = eterm_type::UNDEFINED) - { m_data.s.type = t; m_data.s.name = atom(s); } - var(const std::string& s, eterm_type t = eterm_type::UNDEFINED) - { m_data.s.type = t; m_data.s.name = atom(s); } + var(eterm_type t = UNDEFINED) + { m_type = t; m_name = am_ANY_; } + var(const char* s, eterm_type t = UNDEFINED) + { m_type = t; m_name = atom(s); } + var(const std::string& s, eterm_type t = UNDEFINED) + { m_type = t; m_name = atom(s); } template - var(const std::string& s, eterm_type t = eterm_type::UNDEFINED) - { m_data.s.type = t; m_data.s.name = atom(s); } - var(const char* s, size_t n, eterm_type t = eterm_type::UNDEFINED) - { m_data.s.type = t; m_data.s.name = atom(s, n); } - var(const atom& s, eterm_type t = eterm_type::UNDEFINED) - { m_data.s.type = t; m_data.s.name = s; } - var(const var& v) { m_data.i = v.m_data.i; } - - const char* c_str() const { return m_data.s.name.c_str(); } - const string_t& str() const { return m_data.s.name.to_string(); } - atom name() const { return m_data.s.name; } - size_t length() const { return m_data.s.name.length(); } - - eterm_type type() const { return m_data.s.type; } + var(const string& s, eterm_type t = UNDEFINED) + { m_type = t; m_name = atom(s); } + var(const char* s, size_t n, eterm_type t = UNDEFINED) + { m_type = t; m_name = atom(s, n); } + var(const atom& s, eterm_type t = UNDEFINED) + { m_type = t; m_name = s; } + var(const var& v) { m_type = v.m_type; m_name = v.m_name; } + + const char* c_str() const { return m_name.c_str(); } + const string_t& str() const { return m_name.to_string(); } + atom name() const { return m_name; } + size_t length() const { return m_name.length(); } + + eterm_type type() const { return (eterm_type)m_type; } bool is_any() const { return name() == am_ANY_; } - const string_t& to_string() const { + string_t to_string() const { std::stringstream s; s << name().to_string() << type_to_type_string(type(), true); return s.str(); @@ -102,13 +96,13 @@ class var throw err_encode_exception("Cannot encode vars!"); } - template + template const eterm* find_unbound(const varbind* binding = NULL) const { return binding ? binding->find(name()) : NULL; } - template + template bool subst(eterm& out, const varbind* binding) const throw (err_unbound_variable) { @@ -119,7 +113,7 @@ class var return true; } - template + template bool match(const eterm& pattern, varbind* binding) const throw (err_unbound_variable) { @@ -135,21 +129,23 @@ class var return true; } - template + template std::ostream& dump(std::ostream& out, const varbind* binding = NULL) const { const eterm* term = binding ? binding->find(name()) : NULL; return out << (term && check_type(term->type()) - ? term->to_string(std::string::npos, binding) : *this); + ? term->to_string(std::string::npos, binding) : to_string()); } }; +BOOST_STATIC_ASSERT(sizeof(var) == 8); + } // namespace marshal } // namespace EIXX_NAMESPACE namespace std { template ostream& operator<< (ostream& out, EIXX_NAMESPACE::marshal::var s) { - return s.dump(out); + return s.dump(out, (const EIXX_NAMESPACE::marshal::varbind*)NULL); } } // namespace std diff --git a/include/eixx/marshal/varbind.hpp b/include/eixx/marshal/varbind.hpp index 341a218..39b542d 100644 --- a/include/eixx/marshal/varbind.hpp +++ b/include/eixx/marshal/varbind.hpp @@ -56,7 +56,7 @@ class varbind { public: explicit varbind(const Alloc& a_alloc = Alloc()) - : m_term_map(std::less< string >(), a_alloc) + : m_term_map(std::less(), a_alloc) {} varbind(const varbind& rhs) : m_term_map(rhs.m_term_map) diff --git a/include/eixx/marshal/visit.hpp b/include/eixx/marshal/visit.hpp index 8f3e400..1618049 100644 --- a/include/eixx/marshal/visit.hpp +++ b/include/eixx/marshal/visit.hpp @@ -40,7 +40,7 @@ namespace marshal { template class tuple; template class list; - template class var; + class var; template struct wrap { diff --git a/include/eixx/marshal/visit_subst.hpp b/include/eixx/marshal/visit_subst.hpp index 86b6f1d..79fbe5c 100644 --- a/include/eixx/marshal/visit_subst.hpp +++ b/include/eixx/marshal/visit_subst.hpp @@ -35,7 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include //#include //#include -//#include +#include #include namespace EIXX_NAMESPACE { diff --git a/include/eixx/util/async_wait_timeout.hpp b/include/eixx/util/async_wait_timeout.hpp index baee539..d5ba169 100644 --- a/include/eixx/util/async_wait_timeout.hpp +++ b/include/eixx/util/async_wait_timeout.hpp @@ -32,7 +32,7 @@ namespace error { } static const boost::system::error_category& timer_category - = boost::asio::error::get_timer_category(); + = boost::asio::error::get_timer_category(); } // namespace error } // namespace asio diff --git a/src/am.cpp b/src/am.cpp index da18975..3e8a93d 100644 --- a/src/am.cpp +++ b/src/am.cpp @@ -2,10 +2,10 @@ namespace EIXX_NAMESPACE { - atom am_ANY_ = atom("_"); - atom am_true = atom("true"); - atom am_false = atom("false"); - atom am_undefined = atom("undefined"); + const atom am_ANY_ = atom("_"); + const atom am_true = atom("true"); + const atom am_false = atom("false"); + const atom am_undefined = atom("undefined"); } // namespace EIXX_NAMESPACE diff --git a/src/atom.cpp b/src/atom.cpp index 2faae71..79147c1 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -3,14 +3,12 @@ //#include namespace EIXX_NAMESPACE { -namespace util { - util::atom_table<>& atom::atom_table() { + util::atom_table<>& marshal::atom::atom_table() { //return boost::details::pool::singleton_default >::instance(); static util::atom_table<> s_atom_table; return s_atom_table; } -} // namespace marshal } // namespace EIXX_NAMESPACE diff --git a/src/defaults.cpp b/src/defaults.cpp index f4d1855..65676fa 100644 --- a/src/defaults.cpp +++ b/src/defaults.cpp @@ -41,7 +41,7 @@ namespace EIXX_NAMESPACE { } eterm_type type_string_to_type(const char* s, size_t n) { - eterm_type r = eterm_type::UNDEFINED; + eterm_type r = UNDEFINED; if (n < 3) return r; @@ -50,40 +50,40 @@ namespace EIXX_NAMESPACE { switch (s[0]) { case 'i': - if (strncmp(p,"nt",m) == 0) r = eterm_type::LONG; + if (strncmp(p,"nt",m) == 0) r = LONG; break; case 'd': - if (strncmp(p,"ouble",m) == 0) r = eterm_type::DOUBLE; + if (strncmp(p,"ouble",m) == 0) r = DOUBLE; break; case 'f': - if (strncmp(p,"loat",m) == 0) r = eterm_type::DOUBLE; + if (strncmp(p,"loat",m) == 0) r = DOUBLE; break; case 'b': - if (strncmp(p,"ool",m) == 0) r = eterm_type::BOOL; - else if (strncmp(p,"inary",m) == 0) r = eterm_type::BINARY; + if (strncmp(p,"ool",m) == 0) r = BOOL; + else if (strncmp(p,"inary",m) == 0) r = BINARY; break; case 'a': - if (strncmp(p,"tom",m) == 0) r = eterm_type::ATOM; + if (strncmp(p,"tom",m) == 0) r = ATOM; break; case 's': - if (strncmp(p,"tring",m) == 0) r = eterm_type::STRING; + if (strncmp(p,"tring",m) == 0) r = STRING; break; case 'p': - if (strncmp(p,"id",m) == 0) r = eterm_type::PID; - else if (strncmp(p,"ort",m) == 0) r = eterm_type::PORT; + if (strncmp(p,"id",m) == 0) r = PID; + else if (strncmp(p,"ort",m) == 0) r = PORT; break; case 'r': - if (strncmp(p,"ef",m) == 0) r = eterm_type::REF; + if (strncmp(p,"ef",m) == 0) r = REF; break; case 'v': - if (strncmp(p,"ar",m) == 0) r = eterm_type::VAR; + if (strncmp(p,"ar",m) == 0) r = VAR; break; case 't': - if (strncmp(p,"uple",m) == 0) r = eterm_type::TUPLE; - else if (strncmp(p,"race",m) == 0) r = eterm_type::TRACE; + if (strncmp(p,"uple",m) == 0) r = TUPLE; + else if (strncmp(p,"race",m) == 0) r = TRACE; break; case 'l': - if (strncmp(p,"ist",m) == 0) r = eterm_type::LIST; + if (strncmp(p,"ist",m) == 0) r = LIST; break; default: break; From 17464879408e11156757f5157ad9ffc9a5277f8f Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 3 Oct 2013 15:46:27 -0400 Subject: [PATCH 006/185] Work in progress porting to TR1 --- README | 32 +- configure.ac | 2 +- include/eixx/connect/basic_otp_connection.hpp | 10 +- include/eixx/connect/basic_otp_mailbox.hpp | 14 +- include/eixx/connect/basic_otp_node.ipp | 2 +- .../eixx/connect/transport_otp_connection.hpp | 17 +- .../eixx/connect/transport_otp_connection.ipp | 8 +- .../connect/transport_otp_connection_tcp.hpp | 6 +- .../connect/transport_otp_connection_tcp.ipp | 77 ++-- include/eixx/eterm_exception.hpp | 4 +- include/eixx/marshal/atom.hpp | 3 + include/eixx/marshal/binary.hpp | 38 +- include/eixx/marshal/binary.ipp | 2 +- include/eixx/marshal/defaults.hpp | 18 +- .../marshal/detail/array_variadic_init.hpp | 68 ++++ include/eixx/marshal/eterm.hpp | 271 ++++++++----- include/eixx/marshal/eterm.ipp | 108 +++-- include/eixx/marshal/eterm_format.hpp | 8 + include/eixx/marshal/eterm_format.ipp | 370 +++++++++--------- include/eixx/marshal/eterm_match.hpp | 5 +- include/eixx/marshal/list.hpp | 30 +- include/eixx/marshal/list.ipp | 35 +- include/eixx/marshal/pid.hpp | 57 ++- include/eixx/marshal/port.hpp | 29 +- include/eixx/marshal/ref.hpp | 36 +- include/eixx/marshal/string.hpp | 32 +- include/eixx/marshal/tuple.hpp | 49 ++- include/eixx/marshal/var.hpp | 37 +- include/eixx/util/async_wait_timeout.hpp | 26 +- include/eixx/util/atom_table.hpp | 22 +- src/Makefile.am | 3 +- src/am.cpp | 24 ++ src/atom.cpp | 26 ++ src/basic_otp_node_local.cpp | 4 +- src/defaults.cpp | 9 +- src/ref.cpp | 33 ++ src/server.hpp | 16 +- src/test_node.cpp | 23 +- test/test_eterm.cpp | 50 ++- test/test_eterm_encode.cpp | 2 +- test/test_eterm_format.cpp | 67 +++- test/test_eterm_match.cpp | 192 ++++++++- test/test_mailbox.cpp | 8 +- test/test_node.cpp | 3 +- 44 files changed, 1260 insertions(+), 616 deletions(-) create mode 100644 include/eixx/marshal/detail/array_variadic_init.hpp create mode 100644 src/ref.cpp diff --git a/README b/README index 5885cb2..4cf7423 100644 --- a/README +++ b/README @@ -61,6 +61,36 @@ LICENSE Example ======= +Manipulating Erlang terms is quite simple: + + eterm i = 10; + eterm s = "abc"; + eterm a = atom("ok"); + eterm t = {20.0, i, s, a}; // Constructs a tuple + eterm e = list{}; // Constructs an empty list + eterm l = list{i, 100.0, s, {a, 30}, list{}}; // Constructs a list + + A convenient eterm::format() function implements an expression parser: + + eterm t1 = eterm::format("{ok, 10}"); + eterm t2 = eterm::format("[1, 2, ok, [{one, 10}, {two, 20}]]"); + eterm t3 = eterm::format("A::int()"); // t3 is a variable that can be matched + +Pattern matching is done by constructing a pattern, and matching a term +against it. If varbind is provided, it'll store the values of all matched variables: + + static const eterm s_pattern = eterm::format("{ok, A::string()}"); + + eterm value = {atom("ok"), "abc"}; + + varbind binding; + + if (value.match(s_pattern, &binding)) + std::cout << "Value of variable A: " << binding["A"].to_string() << std::endl; + +Aside from providing functionality that allows to manipulate Erlang terms, this +library implements Erlang distributed transport that allows a C++ program to connect +to an Erlang node, exchange messages, make RPC calls, and receive I/O requests. Here's an example use of the eixx library: void on_message(otp_mailbox& a_mbox, boost::system::error_code& ec) { @@ -71,7 +101,7 @@ Here's an example use of the eixx library: } else { // The mailbox has a queue of transport messages. // Dequeue next message from the mailbox. - boost::scoped_ptr dist_msg; + std::unique_ptr dist_msg; while (dist_msg.reset(a_mbox.receive())) { std::cout << "Main mailbox got a distributed transport message:\n " diff --git a/configure.ac b/configure.ac index f24a218..cd4a9b4 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_ARG_VAR([ERLC_FLAGS], [general flags to prepend to ERLC_FLAGS]) ERLC_FLAGS="${ERLC_FLAGS} +debug_info" # CXXFLAGS="${CXXFLAGS% } -MMD -Wall -fno-strict-aliasing -fpermissive -Wl,-V" -CXXFLAGS="${CXXFLAGS% } -MMD -Wall -fno-strict-aliasing" +CXXFLAGS="${CXXFLAGS% } -MMD -Wall -fno-strict-aliasing -std=c++11 -DBOOST_SYSTEM_NO_DEPRECATED=1" AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debug [[default=no]]]), diff --git a/include/eixx/connect/basic_otp_connection.hpp b/include/eixx/connect/basic_otp_connection.hpp index 5d939d7..4967a1b 100644 --- a/include/eixx/connect/basic_otp_connection.hpp +++ b/include/eixx/connect/basic_otp_connection.hpp @@ -35,9 +35,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_BASIC_OTP_CONNECTION_HPP_ #define _EIXX_BASIC_OTP_CONNECTION_HPP_ +#include #include #include -#include namespace EIXX_NAMESPACE { namespace connect { @@ -46,7 +46,7 @@ template class basic_otp_node; template class basic_otp_connection - : public boost::enable_shared_from_this > { + : public std::enable_shared_from_this > { public: typedef basic_otp_connection self; typedef connection, Alloc> connection_type; @@ -95,8 +95,8 @@ class basic_otp_connection return; m_reconnect_timer.expires_from_now(boost::posix_time::seconds(m_reconnect_secs)); m_reconnect_timer.async_wait( - boost::bind(&self::timer_reconnect, this->shared_from_this(), - boost::asio::placeholders::error)); + std::bind(&self::timer_reconnect, this->shared_from_this(), + std::placeholders::_1)); } void timer_reconnect(const boost::system::error_code& ec) { @@ -115,7 +115,7 @@ class basic_otp_connection } public: - typedef boost::shared_ptr > pointer; + typedef std::shared_ptr > pointer; boost::asio::io_service& io_service() { return m_io_service; } connection_type* transport() { return m_transport.get(); } diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index d7e3cf9..a62cca2 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -36,10 +36,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define _EIXX_BASIC_OTP_MAILBOX_HPP_ #include +#include #include #include #include -#include #include #include @@ -87,7 +87,7 @@ template class basic_otp_mailbox { public: - typedef boost::shared_ptr > pointer; + typedef std::shared_ptr > pointer; typedef boost::function< void (basic_otp_mailbox&, boost::system::error_code&) @@ -178,7 +178,7 @@ class basic_otp_mailbox void deliver(const transport_msg& a_msg) { transport_msg* l_msg = new transport_msg(a_msg); m_io_service.post( - boost::bind( + std::bind( &basic_otp_mailbox::do_deliver, this, l_msg)); } @@ -359,14 +359,14 @@ async_receive(receive_handler_type h, long msec_timeout) throw (std::runtime_err if (msec_timeout < 0) m_deadline_timer.async_wait( - boost::bind( + std::bind( &basic_otp_mailbox::do_on_deadline_timer, - this, h, boost::asio::placeholders::error)); + this, h, std::placeholders::_1)); else m_deadline_timer.async_wait_timeout( - boost::bind( + std::bind( &basic_otp_mailbox::do_on_deadline_timer, - this, h, boost::asio::placeholders::error), + this, h, std::placeholders::_1), msec_timeout); } diff --git a/include/eixx/connect/basic_otp_node.ipp b/include/eixx/connect/basic_otp_node.ipp index 2b5fa6a..faefdb7 100644 --- a/include/eixx/connect/basic_otp_node.ipp +++ b/include/eixx/connect/basic_otp_node.ipp @@ -116,7 +116,7 @@ void basic_otp_node::connect( m_connections[a_remote_node] = con; } else { std::string e; - m_io_service.post(boost::bind(h, &*it->second, e)); + m_io_service.post(std::bind(h, &*it->second, e)); } } diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index 4761177..0d22730 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -33,11 +33,11 @@ #ifndef _EIXX_TRANSPORT_OTP_CONNECTION_HPP_ #define _EIXX_TRANSPORT_OTP_CONNECTION_HPP_ +#include #include #include #include #include -#include #include #include #include @@ -65,7 +65,7 @@ const char* connection_type_to_str(connection_type a_type); template class connection : private boost::noncopyable - , public boost::enable_shared_from_this< connection > + , public std::enable_shared_from_this< connection > { protected: static const size_t s_header_size; @@ -161,8 +161,8 @@ class connection m_handler->report_status(REPORT_INFO, s.str()); } async_write(buffers, boost::asio::transfer_all(), - boost::bind(&connection::handle_write, this->shared_from_this(), - boost::asio::placeholders::error)); + std::bind(&connection::handle_write, this->shared_from_this(), + std::placeholders::_1)); } } @@ -210,7 +210,7 @@ class connection boost::asio::const_buffer b(data, sz); m_io_service.post( - boost::bind(&connection::do_write, this->shared_from_this(), b)); + std::bind(&connection::do_write, this->shared_from_this(), b)); } /// Get connection type from string. If successful the string is @@ -253,9 +253,8 @@ class connection async_read( buffers, boost::asio::transfer_at_least(s_header_size), - boost::bind(&connection::handle_read, this->shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + std::bind(&connection::handle_read, this->shared_from_this(), + std::placeholders::_1, std::placeholders::_2)); } template @@ -266,7 +265,7 @@ class connection public: typedef Handler handler_type; - typedef boost::shared_ptr > pointer; + typedef std::shared_ptr > pointer; /// Create a connection object given of specific type and connect to peer /// endpoint given by \a a_addr. diff --git a/include/eixx/connect/transport_otp_connection.ipp b/include/eixx/connect/transport_otp_connection.ipp index f5bdf58..dfb384c 100644 --- a/include/eixx/connect/transport_otp_connection.ipp +++ b/include/eixx/connect/transport_otp_connection.ipp @@ -347,9 +347,9 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) boost::asio::mutable_buffers_1 buffers(m_rd_end, rd_capacity()); async_read( buffers, boost::asio::transfer_at_least(need_bytes), - boost::bind(&connection::handle_read, this->shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + std::bind(&connection::handle_read, this->shared_from_this(), + std::placeholders::_1, + std::placeholders::_2)); } /// Decode distributed Erlang message. The message must be fully @@ -485,7 +485,7 @@ send(const transport_msg& a_msg) boost::asio::const_buffer b(data, len); m_io_service.post( - boost::bind(&connection::do_write, this->shared_from_this(), b)); + std::bind(&connection::do_write, this->shared_from_this(), b)); } } // namespace connect diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 5ae4c42..6327fad 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -146,9 +146,9 @@ class tcp_connection const std::string& a_remote_node, const std::string& a_cookie) throw(std::runtime_error); - boost::shared_ptr > shared_from_this() { - boost::shared_ptr > p = base_t::shared_from_this(); - return *reinterpret_cast >*>(&p); + std::shared_ptr > shared_from_this() { + std::shared_ptr > p = base_t::shared_from_this(); + return *reinterpret_cast >*>(&p); } /// Set the socket to non-blocking mode and issue on_connect() callback. diff --git a/include/eixx/connect/transport_otp_connection_tcp.ipp b/include/eixx/connect/transport_otp_connection_tcp.ipp index 973be77..dabe574 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.ipp +++ b/include/eixx/connect/transport_otp_connection_tcp.ipp @@ -83,9 +83,8 @@ void tcp_connection::connect( tcp::resolver::query q(remote_hostname(), epmd_port); m_state = CS_WAIT_RESOLVE; m_resolver.async_resolve(q, - boost::bind(&tcp_connection::handle_resolve, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::iterator)); + std::bind(&tcp_connection::handle_resolve, shared_from_this(), + std::placeholders::_1, std::placeholders::_2)); } template @@ -104,8 +103,8 @@ void tcp_connection::handle_resolve( m_peer_endpoint = *ep_iterator; m_state = CS_WAIT_EPMD_CONNECT; m_socket.async_connect(m_peer_endpoint, - boost::bind(&tcp_connection::handle_epmd_connect, shared_from_this(), - boost::asio::placeholders::error, ++ep_iterator)); + std::bind(&tcp_connection::handle_epmd_connect, shared_from_this(), + std::placeholders::_1, ++ep_iterator)); } template @@ -131,15 +130,15 @@ void tcp_connection::handle_epmd_connect( m_state = CS_WAIT_EPMD_WRITE_DONE; boost::asio::async_write(m_socket, boost::asio::buffer(m_buf_epmd, len+2), - boost::bind(&tcp_connection::handle_epmd_write, shared_from_this(), - boost::asio::placeholders::error)); + std::bind(&tcp_connection::handle_epmd_write, shared_from_this(), + std::placeholders::_1)); } else if (ep_iterator != boost::asio::ip::tcp::resolver::iterator()) { // The connection failed. Try the next endpoint in the list. m_socket.close(); m_peer_endpoint = *ep_iterator; m_socket.async_connect(m_peer_endpoint, - boost::bind(&tcp_connection::handle_epmd_connect, shared_from_this(), - boost::asio::placeholders::error, ++ep_iterator)); + std::bind(&tcp_connection::handle_epmd_connect, shared_from_this(), + std::placeholders::_1, ++ep_iterator)); } else { std::stringstream str; str << "Error connecting to epmd at host '" << this->remote_node() << "': " << err.message(); @@ -164,9 +163,9 @@ void tcp_connection::handle_epmd_write(const boost::system::erro m_epmd_wr = m_buf_epmd; boost::asio::async_read(m_socket, boost::asio::buffer(m_buf_epmd, sizeof(m_buf_epmd)), boost::asio::transfer_at_least(2), - boost::bind(&tcp_connection::handle_epmd_read_header, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + std::bind(&tcp_connection::handle_epmd_read_header, shared_from_this(), + std::placeholders::_1, + std::placeholders::_2)); } template @@ -216,9 +215,9 @@ void tcp_connection::handle_epmd_read_header( boost::asio::async_read(m_socket, boost::asio::buffer(m_epmd_wr, sizeof(m_buf_epmd)-bytes_transferred), boost::asio::transfer_at_least(need_bytes), - boost::bind(&tcp_connection::handle_epmd_read_body, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + std::bind(&tcp_connection::handle_epmd_read_body, shared_from_this(), + std::placeholders::_1, + std::placeholders::_2)); } else { handle_epmd_read_body(boost::system::error_code(), 0); } @@ -274,8 +273,8 @@ void tcp_connection::handle_epmd_read_body( m_state = CS_WAIT_CONNECT; m_socket.async_connect(m_peer_endpoint, - boost::bind(&tcp_connection::handle_connect, shared_from_this(), - boost::asio::placeholders::error)); + std::bind(&tcp_connection::handle_connect, shared_from_this(), + std::placeholders::_1)); } template @@ -330,8 +329,8 @@ void tcp_connection::handle_connect(const boost::system::error_c m_state = CS_WAIT_WRITE_CHALLENGE_DONE; boost::asio::async_write(m_socket, boost::asio::buffer(m_buf_node, siz), - boost::bind(&tcp_connection::handle_write_name, shared_from_this(), - boost::asio::placeholders::error)); + std::bind(&tcp_connection::handle_write_name, shared_from_this(), + std::placeholders::_1)); } template @@ -348,9 +347,9 @@ void tcp_connection::handle_write_name(const boost::system::erro m_state = CS_WAIT_STATUS; boost::asio::async_read(m_socket, boost::asio::buffer(m_buf_node, sizeof(m_buf_node)), boost::asio::transfer_at_least(2), - boost::bind(&tcp_connection::handle_read_status_header, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + std::bind(&tcp_connection::handle_read_status_header, shared_from_this(), + std::placeholders::_1, + std::placeholders::_2)); } template @@ -384,9 +383,9 @@ void tcp_connection::handle_read_status_header( boost::asio::async_read(m_socket, boost::asio::buffer(m_node_wr, (m_buf_node+1) - m_node_wr), boost::asio::transfer_at_least(need_bytes), - boost::bind(&tcp_connection::handle_read_status_body, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + std::bind(&tcp_connection::handle_read_status_body, shared_from_this(), + std::placeholders::_1, + std::placeholders::_2)); } else { handle_read_status_body(boost::system::error_code(), 0); } @@ -427,9 +426,9 @@ void tcp_connection::handle_read_status_body( else boost::asio::async_read(m_socket, boost::asio::buffer(m_node_wr, (m_buf_node+1) - m_node_wr), boost::asio::transfer_at_least(2), - boost::bind(&tcp_connection::handle_read_challenge_header, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + std::bind(&tcp_connection::handle_read_challenge_header, shared_from_this(), + std::placeholders::_1, + std::placeholders::_2)); } template @@ -461,9 +460,9 @@ void tcp_connection::handle_read_challenge_header( boost::asio::async_read(m_socket, boost::asio::buffer(m_node_wr, (m_buf_node+1) - m_node_wr), boost::asio::transfer_at_least(need_bytes), - boost::bind(&tcp_connection::handle_read_challenge_body, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + std::bind(&tcp_connection::handle_read_challenge_body, shared_from_this(), + std::placeholders::_1, + std::placeholders::_2)); } else { handle_read_challenge_body(boost::system::error_code(), 0); } @@ -528,8 +527,8 @@ void tcp_connection::handle_read_challenge_body( m_state = CS_WAIT_WRITE_CHALLENGE_REPLY_DONE; boost::asio::async_write(m_socket, boost::asio::buffer(m_buf_node, siz), - boost::bind(&tcp_connection::handle_write_challenge_reply, shared_from_this(), - boost::asio::placeholders::error)); + std::bind(&tcp_connection::handle_write_challenge_reply, shared_from_this(), + std::placeholders::_1)); } template @@ -546,9 +545,9 @@ void tcp_connection::handle_write_challenge_reply(const boost::s m_state = CS_WAIT_CHALLENGE_ACK; boost::asio::async_read(m_socket, boost::asio::buffer(m_buf_node, sizeof(m_buf_node)), boost::asio::transfer_at_least(2), - boost::bind(&tcp_connection::handle_read_challenge_ack_header, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + std::bind(&tcp_connection::handle_read_challenge_ack_header, shared_from_this(), + std::placeholders::_1, + std::placeholders::_2)); } template @@ -583,10 +582,10 @@ void tcp_connection::handle_read_challenge_ack_header( boost::asio::async_read(m_socket, boost::asio::buffer(m_node_wr, (m_buf_node+1)-m_node_wr), boost::asio::transfer_at_least(need_bytes), - boost::bind(&tcp_connection::handle_read_challenge_ack_body, + std::bind(&tcp_connection::handle_read_challenge_ack_body, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + std::placeholders::_1, + std::placeholders::_2)); } else { handle_read_challenge_ack_body(boost::system::error_code(), 0); } diff --git a/include/eixx/eterm_exception.hpp b/include/eixx/eterm_exception.hpp index 3ad9eda..eaad2a0 100644 --- a/include/eixx/eterm_exception.hpp +++ b/include/eixx/eterm_exception.hpp @@ -129,9 +129,11 @@ class err_format_exception: public eterm_exception { const char* m_pos; const char* m_start; public: - err_format_exception(const std::string &msg, const char* pos) + err_format_exception( + const std::string &msg, const char* pos, const char* start = nullptr) : eterm_exception(msg) , m_pos(pos) + , m_start(start) {} const char* what() const throw() { diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index dd051e5..ed69572 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -76,6 +76,9 @@ class atom public: static util::atom_table<>& atom_table(); + /// Returns empty atom + static const atom null; + /// Create an empty atom atom() : m_index(0) { BOOST_STATIC_ASSERT(sizeof(atom) == 4); diff --git a/include/eixx/marshal/binary.hpp b/include/eixx/marshal/binary.hpp index 06bea45..02c66e3 100644 --- a/include/eixx/marshal/binary.hpp +++ b/include/eixx/marshal/binary.hpp @@ -51,8 +51,9 @@ class binary void decode(const char* buf, int& idx, size_t size) throw(err_decode_exception); - binary() {} public: + binary() : m_blob(nullptr) {} + /** * Create a binary from the given data. * Data is shared between all cloned binaries by using reference counting. @@ -60,15 +61,24 @@ class binary * @param size binary size in bytes * @param a_alloc is the allocator to use **/ - binary(const char* data, size_t size, const Alloc& a_alloc = Alloc()) - : m_blob(new blob(size, a_alloc)) { + binary(const char* data, size_t size, const Alloc& a_alloc = Alloc()) { + if (size == 0) { + m_blob = nullptr; + return; + } + m_blob = new blob(size, a_alloc); memcpy(m_blob->data(), data, size); } binary(const binary& rhs) : m_blob(rhs.m_blob) { - m_blob->inc_rc(); + if (m_blob) m_blob->inc_rc(); } + binary(binary&& rhs) : m_blob(rhs.m_blob) { rhs.m_blob = nullptr; } + + binary(std::initializer_list bytes, const Alloc& alloc = Alloc()) + : binary(reinterpret_cast(bytes.begin()), bytes.size(), alloc) {} + /** * Construct the object by decoding it from a binary * encoded buffer and using custom allocator. @@ -81,10 +91,26 @@ class binary throw(err_decode_exception); /** Get the size of the data (in bytes) */ - size_t size() const { return m_blob->size(); } + size_t size() const { return m_blob ? m_blob->size() : 0; } /** Get the data's binary buffer */ - char* data() const { return m_blob->data(); } + const char* data() const { return m_blob ? m_blob->data() : ""; } + + binary& operator= (const binary& rhs) { + if (this != &rhs) { + m_blob = rhs.m_blob; + if (m_blob) m_blob->inc_rc(); + } + return *this; + } + + binary& operator= (binary&& rhs) { + if (this != &rhs) { + m_blob = rhs.m_blob; + rhs.m_blob = nullptr; + } + return *this; + } bool operator== (const binary& rhs) const { return size() == rhs.size() diff --git a/include/eixx/marshal/binary.ipp b/include/eixx/marshal/binary.ipp index ce521e9..bec96d5 100644 --- a/include/eixx/marshal/binary.ipp +++ b/include/eixx/marshal/binary.ipp @@ -49,7 +49,7 @@ binary::binary(const char* buf, int& idx, size_t size, const Alloc& a_all size_t sz = get32be(s); m_blob = new blob(sz, a_alloc); - ::memcpy(data(),s,sz); + ::memcpy(m_blob->data(),s,sz); idx += s + sz - s0; BOOST_ASSERT((size_t)idx <= size); diff --git a/include/eixx/marshal/defaults.hpp b/include/eixx/marshal/defaults.hpp index 439fcff..9db1baf 100644 --- a/include/eixx/marshal/defaults.hpp +++ b/include/eixx/marshal/defaults.hpp @@ -74,14 +74,14 @@ namespace EIXX_NAMESPACE { , LONG = 1 , DOUBLE = 2 , BOOL = 3 - // ATOM is the first compound item having a constructor , ATOM = 4 - , STRING = 5 - , BINARY = 6 - , PID = 7 - , PORT = 8 - , REF = 9 - , VAR = 10 + , VAR = 5 + // STRING is the first compound item that requires destruction + , STRING = 6 + , BINARY = 7 + , PID = 8 + , PORT = 9 + , REF = 10 , TUPLE = 11 , LIST = 12 , TRACE = 13 @@ -99,10 +99,10 @@ namespace EIXX_NAMESPACE { /// Outputs: ::bool() const char* type_to_type_string(eterm_type a_type, bool a_prefix=false); - /// Converts a string to eterm type + /// Converts a string to eterm type (e.g. "binary" -> eterm_type::BINARY) eterm_type type_string_to_type(const char* s, size_t n); - /// Converts a string \a s to eterm type + /// Converts a string \a s to eterm type (e.g. "binary" -> eterm_type::BINARY) inline eterm_type type_string_to_type(const char* s) { return type_string_to_type(s, strlen(s)); } diff --git a/include/eixx/marshal/detail/array_variadic_init.hpp b/include/eixx/marshal/detail/array_variadic_init.hpp new file mode 100644 index 0000000..efafbcb --- /dev/null +++ b/include/eixx/marshal/detail/array_variadic_init.hpp @@ -0,0 +1,68 @@ +//---------------------------------------------------------------------------- +/// \file array_variadic_init.hpp +//---------------------------------------------------------------------------- +/// \brief Copies variadic parameters to an array +//---------------------------------------------------------------------------- +// Copyright (c) 2013 Serge Aleynikov +// Created: 2013-10-05 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the eixx (Erlang C++ Interface) Library. + +Copyright (C) 2013 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ +#ifndef _EIXX_ARRAY_VARIADIC_INIT_HPP_ +#define _EIXX_ARRAY_VARIADIC_INIT_HPP_ + +#include + +namespace EIXX_NAMESPACE { +namespace marshal { +namespace detail { + + namespace { + template + struct init_array { + static void set(eterm* a_array, const Head& v, const Tail&... tail) { + a_array[I] = eterm(v); + init_array::set(a_array, tail...); + } + }; + + template + struct init_array { + static void set(eterm* a_array, const Head& v) { + a_array[I] = eterm(v); + } + }; + } + + template + void initialize(eterm* a_target, Args... args) + { + init_array<0, Args...>::set(a_target, args...); + } + +} // namespace detail +} // namespace marshal +} // namespace EIXX_NAMESPACE + +#endif // _EIXX_ARRAY_VARIADIC_INIT_HPP_ diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index c82b9f4..78eee45 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -38,6 +38,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include +#include + #include // Must be included before any #include @@ -131,32 +133,57 @@ class eterm { eterm_type m_type; union vartype { - long i; - double d; - bool b; - // Since a union cannot have types that have constructors, - // we allocate space for a pointer to a compound type, and using - // that space to store the value of the compound type. - // Additionally, we ensure that the size of each compound type + double d; + bool b; + long i; + atom a; + var v; + string s; + binary bin; + epid pid; + port prt; + ref r; + tuple t; + list l; + trace trc; + + void* value; // this is for ease of copying + + // We ensure that the size of each compound type // is sizeof(void*). Therefore it's safe to store the actual // value of a compound type in this union, so the pointer serves // as the value placeholder. - // This trick allows us to have minimum overhead related to + // This allows us to have the minimum overhead related to // copying terms as for simple types it merely involves copying // 16 bytes (64-bit platform) and for compound types it means copying // the same 16 bytes and in some cases // incrementing compound type's reference count. // This approach was tested against boost::variant<> and was found // to be several times more efficient. - void* p; /* Space for any compound reference-counted value with constructor */ - - template - operator T& () { return reinterpret_cast(p); } - template - operator const T& () const { return reinterpret_cast(p); } + vartype(int x) : i(x) {} + vartype(long x) : i(x) {} + vartype(double x) : d(x) {} + vartype(bool x) : b(x) {} + vartype(atom x) : a(x) {} + vartype(var x) : v(x) {} + vartype(const string& x) : s(x) {} + vartype(const binary& x) : bin(x) {} + vartype(const epid& x) : pid(x) {} + vartype(const port& x) : prt(x) {} + vartype(const ref& x) : r(x) {} + vartype(const tuple& x) : t(x) {} + vartype(const list& x) : l(x) {} + vartype(const trace& x) : trc(x) {} + + vartype() : i(0) {} + ~vartype() {} + + void reset() { i = 0; } } vt; + BOOST_STATIC_ASSERT(sizeof(vartype) == sizeof(void*)); + void check(eterm_type tp) const { if (unlikely(m_type != tp)) throw err_wrong_type(tp, m_type); } /** @@ -168,46 +195,65 @@ class eterm { long& get(long*) { check(LONG); return vt.i; } double& get(double*) { check(DOUBLE); return vt.d; } bool& get(bool*) { check(BOOL); return vt.b; } - atom& get(const atom*) { check(ATOM); return vt; } - string& get(const string*) { check(STRING); return vt; } - binary& get(const binary*) { check(BINARY); return vt; } - epid& get(const epid*) { check(PID); return vt; } - port& get(const port*) { check(PORT); return vt; } - ref& get(const ref*) { check(REF); return vt; } - var& get(const var*) { check(VAR); return vt; } - tuple& get(const tuple*) { check(TUPLE); return vt; } - list& get(const list*) { check(LIST); return vt; } - trace& get(const trace*) { check(TRACE); return vt; } + atom& get(const atom*) { check(ATOM); return vt.a; } + var& get(const var*) { check(VAR); return vt.v; } + string& get(const string*) { check(STRING); return vt.s; } + binary& get(const binary*) { check(BINARY); return vt.bin; } + epid& get(const epid*) { check(PID); return vt.pid; } + port& get(const port*) { check(PORT); return vt.prt; } + ref& get(const ref*) { check(REF); return vt.r; } + tuple& get(const tuple*) { check(TUPLE); return vt.t; } + list& get(const list*) { check(LIST); return vt.l; } + trace& get(const trace*) { check(TRACE); return vt.trc; } template friend T& get(eterm& t); + void replace(eterm* a) { + m_type = a->m_type; + vt.value = a->vt.value; + a->m_type = UNDEFINED; + a->vt.reset(); + } + + static eterm format(const Alloc& a_alloc, const char** fmt, va_list* args) + throw (err_format_exception); + + static void format(const Alloc& a_alloc, atom& m, atom& f, eterm& args, + const char** fmt, va_list* pa) throw (err_format_exception); + public: eterm_type type() const { return m_type; } const char* type_string() const; - eterm() : m_type(UNDEFINED) { vt.p = NULL; } + eterm() : m_type(UNDEFINED) {} - eterm(unsigned int a) : m_type(LONG) { vt.i = a; } - eterm(unsigned long a) : m_type(LONG) { vt.i = a; } - eterm(int a) : m_type(LONG) { vt.i = a; } + eterm(unsigned int a) : m_type(LONG), vt((int)a) {} + eterm(unsigned long a) : m_type(LONG), vt((long)a) {} + eterm(int a) : m_type(LONG), vt(a) {} - eterm(long a) : m_type(LONG) { vt.i = a; } - eterm(double a) : m_type(DOUBLE) { vt.d = a; } - eterm(bool a) : m_type(BOOL) { vt.b = a; } + eterm(long a) : m_type(LONG), vt(a) {} + eterm(double a) : m_type(DOUBLE),vt(a) {} + eterm(bool a) : m_type(BOOL), vt(a) {} + eterm(atom a) : m_type(ATOM), vt(a) {} + eterm(var a) : m_type(VAR), vt(a) {} eterm(const char* a, const Alloc& alloc = Alloc()) - : m_type(STRING) { new (&vt.p) string(a, alloc); } + : m_type(STRING), vt(string(a, alloc)) {} eterm(const std::string& a, const Alloc& alloc = Alloc()) - : m_type(STRING) { new (&vt.p) string(a.c_str(), a.size(), alloc); } - eterm(const atom& a) : m_type(ATOM) { new (&vt.p) atom(a); } - eterm(const string& a) : m_type(STRING) { new (&vt.p) string(a);} - eterm(const binary& a) : m_type(BINARY) { new (&vt.p) binary(a);} - eterm(const epid& a) : m_type(PID) { new (&vt.p) epid(a); } - eterm(const port& a) : m_type(PORT) { new (&vt.p) port(a); } - eterm(const ref& a) : m_type(REF) { new (&vt.p) ref(a); } - eterm(const var& a) : m_type(VAR) { new (&vt.p) var(a); } - eterm(const tuple& a) : m_type(TUPLE) { new (&vt.p) tuple(a); } - eterm(const list& a) : m_type(LIST) { new (&vt.p) list(a); } - eterm(const trace& a) : m_type(TRACE) { new (&vt.p) trace(a); } + : m_type(STRING), vt(string(a.c_str(), a.size(), alloc)) {} + eterm(const string& a) : m_type(STRING), vt(a) {} + eterm(const binary& a) : m_type(BINARY), vt(a) {} + eterm(const epid& a) : m_type(PID), vt(a) {} + eterm(const port& a) : m_type(PORT), vt(a) {} + eterm(const ref& a) : m_type(REF), vt(a) {} + eterm(const tuple& a) : m_type(TUPLE), vt(a) {} + eterm(const list& a) : m_type(LIST), vt(a) {} + eterm(const trace& a) : m_type(TRACE), vt(a) {} + + /** + * Tuple initialization + */ + eterm(std::initializer_list> items, const Alloc& alloc = Alloc()) + : eterm(tuple(items, alloc)) {} /** * Construct a term by decoding it from the begining of @@ -239,23 +285,27 @@ class eterm { * and for compound terms the storage is reference counted. */ eterm(const eterm& a) : m_type(a.m_type) { - BOOST_STATIC_ASSERT(sizeof(vartype) == sizeof(void*)); switch (m_type) { - case ATOM: { const atom& t = a.vt; new (&vt.p) atom(t); break; } - case STRING: { const string& t = a.vt; new (&vt.p) string(t); break; } - case BINARY: { const binary& t = a.vt; new (&vt.p) binary(t); break; } - case PID: { const epid& t = a.vt; new (&vt.p) epid(t); break; } - case PORT: { const port& t = a.vt; new (&vt.p) port(t); break; } - case REF: { const ref& t = a.vt; new (&vt.p) ref(t); break; } - case VAR: { const var& t = a.vt; new (&vt.p) var(t); break; } - case TUPLE: { const tuple& t = a.vt; new (&vt.p) tuple(t); break; } - case LIST: { const list& t = a.vt; new (&vt.p) list(t); break; } - case TRACE: { const trace& t = a.vt; new (&vt.p) trace(t); break; } + case STRING: { new (&vt.s) string(a.vt.s); break; } + case BINARY: { new (&vt.bin) binary(a.vt.bin); break; } + case PID: { new (&vt.pid) epid(a.vt.pid); break; } + case PORT: { new (&vt.prt) port(a.vt.prt); break; } + case REF: { new (&vt.r) ref(a.vt.r); break; } + case TUPLE: { new (&vt.t) tuple(a.vt.t); break; } + case LIST: { new (&vt.l) list(a.vt.l); break; } + case TRACE: { new (&vt.trc) trace(a.vt.trc); break; } default: - vt.i = a.vt.i; + vt.value = a.vt.value; } } + /** + * Move constructor + */ + eterm(eterm&& a) { + replace(&a); + } + /** * Destruct this term. For compound terms it decreases the * reference count of their storage. This does nothing to @@ -264,15 +314,14 @@ class eterm { ~eterm() { switch (m_type) { //No need to destruct atoms - they are stored in global atom table. - //case ATOM: { atom& v = vt; v.~atom(); return; } - case STRING: { string& v = vt; v.~string(); return; } - case BINARY: { binary& v = vt; v.~binary(); return; } - case PID: { epid& v = vt; v.~epid(); return; } - case PORT: { port& v = vt; v.~port(); return; } - case REF: { ref& v = vt; v.~ref(); return; } - case TUPLE: { tuple& v = vt; v.~tuple(); return; } - case LIST: { list& v = vt; v.~list(); return; } - case TRACE: { trace& v = vt; v.~trace(); return; } + case STRING: { vt.s.~string(); return; } + case BINARY: { vt.bin.~binary(); return; } + case PID: { vt.pid.~epid(); return; } + case PORT: { vt.prt.~port(); return; } + case REF: { vt.r.~ref(); return; } + case TUPLE: { vt.t.~tuple(); return; } + case LIST: { vt.l.~list(); return; } + case TRACE: { vt.trc.~trace(); return; } default: return; } } @@ -286,11 +335,24 @@ class eterm { // For some reason the template version above doesn't work for eterm parameter // so we overload it explicitely. - void operator= (const eterm& a) { if (this != &a) set(a); } + eterm& operator= (const eterm& a) { if (this != &a) set(a); return *this; } + + /** + * Assign the value to this term. If current term has been initialized, + * its old value is destructed. + */ + eterm& operator= (eterm&& a) { + if (this != &a) { + if (m_type >= STRING) + this->~eterm(); + replace(&a); + } + return *this; + } template void set(const T& a) { - if (m_type > ATOM) + if (m_type >= STRING) this->~eterm(); new (this) eterm(a); } @@ -314,9 +376,9 @@ class eterm { */ bool initialized() const { switch (type()) { - case TUPLE: { const tuple& v = vt; return v.initialized(); } - case LIST: { const list& v = vt; return v.initialized(); } - case TRACE: { const trace& v = vt; return v.initialized(); } + case TUPLE: { return vt.t.initialized(); } + case LIST: { return vt.l.initialized(); } + case TRACE: { return vt.trc.initialized(); } default: return true; } } @@ -327,7 +389,7 @@ class eterm { * they point to the same storage */ bool equals(const eterm& rhs) const { - return m_type == rhs.m_type && vt.i == rhs.vt.i; + return m_type == rhs.m_type && vt.value == rhs.vt.value; } /** @@ -343,19 +405,19 @@ class eterm { long to_long() const { check(LONG); return vt.i; } double to_double() const { check(DOUBLE); return vt.d; } bool to_bool() const { check(BOOL); return vt.b; } - const atom& to_atom() const { check(ATOM); return vt; } - const string& to_str() const { check(STRING); return vt; } - const binary& to_binary() const { check(BINARY); return vt; } - const epid& to_pid() const { check(PID); return vt; } - const port& to_port() const { check(PORT); return vt; } - const ref& to_ref() const { check(REF); return vt; } - const var& to_var() const { check(VAR); return vt; } - const tuple& to_tuple() const { check(TUPLE); return vt; } - tuple& to_tuple() { check(TUPLE); return vt; } - const list& to_list() const { check(LIST); return vt; } - list& to_list() { check(LIST); return vt; } - const trace& to_trace() const { check(TRACE); return vt; } - trace& to_trace() { check(TRACE); return vt; } + const atom& to_atom() const { check(ATOM); return vt.a; } + const var& to_var() const { check(VAR); return vt.v; } + const string& to_str() const { check(STRING); return vt.s; } + const binary& to_binary() const { check(BINARY); return vt.bin; } + const epid& to_pid() const { check(PID); return vt.pid; } + const port& to_port() const { check(PORT); return vt.prt; } + const ref& to_ref() const { check(REF); return vt.r; } + const tuple& to_tuple() const { check(TUPLE); return vt.t; } + tuple& to_tuple() { check(TUPLE); return vt.t; } + const list& to_list() const { check(LIST); return vt.l; } + list& to_list() { check(LIST); return vt.l; } + const trace& to_trace() const { check(TRACE); return vt.trc; } + trace& to_trace() { check(TRACE); return vt.trc; } // Checks if database of the term is of given type @@ -455,13 +517,13 @@ class eterm { * * The set of valid format specifiers is as follows: *
    - *
  • a - An atom - *
  • s - A string - *
  • i - An integer - *
  • l - A long integer - *
  • u - An unsigned long integer - *
  • f - A double float - *
  • w - A pointer to some arbitrary term passed as argument + *
  • a - An atom
  • + *
  • s - A string
  • + *
  • i - An integer
  • + *
  • l - A long integer
  • + *
  • u - An unsigned long integer
  • + *
  • f - A double float
  • + *
  • w - A pointer to some arbitrary term passed as argument
  • *
* * Example: @@ -477,6 +539,15 @@ class eterm { static eterm format(const char* fmt, ...) throw (err_format_exception); + /** + * Same as format(a_alloc, fmt, ...), but parses string in format: + * "Module:Function(Arg1, Arg2, ...) + */ + static void format(const Alloc& a_alloc, atom& mod, atom& fun, eterm& args, + const char* fmt, ...) throw (err_format_exception); + static void format(atom& mod, atom& fun, eterm& args, const char* fmt, ...) + throw (err_format_exception); + /// Cast a value to eterm. If t is of eterm type, it is returned as is. template static eterm cast(T t) { return eterm(t); } @@ -491,16 +562,16 @@ class eterm { case LONG: return wrapper(v, vt.i); case DOUBLE: return wrapper(v, vt.d); case BOOL: return wrapper(v, vt.b); - case ATOM: { const atom& t = vt; return wrapper(v, t); } - case STRING: { const string& t = vt; return wrapper(v, t); } - case BINARY: { const binary& t = vt; return wrapper(v, t); } - case PID: { const epid& t = vt; return wrapper(v, t); } - case PORT: { const port& t = vt; return wrapper(v, t); } - case REF: { const ref& t = vt; return wrapper(v, t); } - case VAR: { const var& t = vt; return wrapper(v, t); } - case TUPLE: { const tuple& t = vt; return wrapper(v, t); } - case LIST: { const list& t = vt; return wrapper(v, t); } - case TRACE: { const trace& t = vt; return wrapper(v, t); } + case ATOM: return wrapper(v, vt.a); + case VAR: return wrapper(v, vt.v); + case STRING: return wrapper(v, vt.s); + case BINARY: return wrapper(v, vt.bin); + case PID: return wrapper(v, vt.pid); + case PORT: return wrapper(v, vt.prt); + case REF: return wrapper(v, vt.r); + case TUPLE: return wrapper(v, vt.t); + case LIST: return wrapper(v, vt.l); + case TRACE: return wrapper(v, vt.trc); default: { std::stringstream s; s << "Undefined term_type (" << m_type << ')'; throw err_invalid_term(s.str()); diff --git a/include/eixx/marshal/eterm.ipp b/include/eixx/marshal/eterm.ipp index e30a599..91be35d 100644 --- a/include/eixx/marshal/eterm.ipp +++ b/include/eixx/marshal/eterm.ipp @@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***** END LICENSE BLOCK ***** */ +#include #include #include #include @@ -66,19 +67,19 @@ inline bool eterm::operator== (const eterm& rhs) const { if (m_type != rhs.type()) return false; switch (m_type) { - case LONG: return vt.i == rhs.to_long(); - case DOUBLE: return vt.d == rhs.to_double(); - case BOOL: return vt.b == rhs.to_bool(); - case ATOM: return vt.p == rhs.vt.p; // We just need to check for the same value - case STRING: { const string& t = vt; return t == rhs.to_str(); } - case BINARY: { const binary& t = vt; return t == rhs.to_binary();} - case PID: { const epid& t = vt; return t == rhs.to_pid(); } - case PORT: { const port& t = vt; return t == rhs.to_port(); } - case REF: { const ref& t = vt; return t == rhs.to_ref(); } - case VAR: { const var& t = vt; return t == rhs.to_var(); } - case TUPLE: { const tuple& t = vt; return t == rhs.to_tuple(); } - case LIST: { const list& t = vt; return t == rhs.to_list(); } - case TRACE: { const trace& t = vt; return t == rhs.to_trace(); } + case LONG: return vt.i == rhs.vt.i; + case DOUBLE: return vt.d == rhs.vt.d; + case BOOL: return vt.b == rhs.vt.b; + case ATOM: return vt.a == rhs.vt.a; + case VAR: return vt.v == rhs.vt.v; + case STRING: return vt.s == rhs.vt.s; + case BINARY: return vt.bin == rhs.vt.bin; + case PID: return vt.pid == rhs.vt.pid; + case PORT: return vt.prt == rhs.vt.prt; + case REF: return vt.r == rhs.vt.r; + case TUPLE: return vt.t == rhs.vt.t; + case LIST: return vt.l == rhs.vt.l; + case TRACE: return vt.trc == rhs.vt.trc; default: { std::stringstream s; s << "Undefined term_type (" << m_type << ')'; throw err_invalid_term(s.str()); @@ -90,7 +91,7 @@ inline bool eterm::operator== (const eterm& rhs) const { template std::string eterm::to_string(size_t a_size_limit, const varbind* binding) const { if (m_type == UNDEFINED) - return ""; + return std::string(); std::ostringstream out; visit_eterm_stringify visitor(out, binding); visitor.apply_visitor(*this); @@ -126,10 +127,13 @@ void eterm::decode(const char* a_buf, int& idx, size_t a_size, const Allo switch (type) { case ERL_ATOM_EXT: { int b; - if (ei_decode_boolean(a_buf, &idx, &b) < 0) + int i = idx; // TODO: Eliminate this variable when there's is a fix for the bug in ei_decode_boolean + if (ei_decode_boolean(a_buf, &i, &b) < 0) new (this) eterm(atom(a_buf, idx, a_size)); - else + else { + idx = i; new (this) eterm((bool)b); + } break; } case ERL_LARGE_TUPLE_EXT: @@ -276,43 +280,71 @@ bool eterm::subst(eterm& out, const varbind* binding) const } template -eterm eterm::format(const Alloc& a_alloc, const char* fmt, ...) +eterm eterm::format(const Alloc& a_alloc, const char** fmt, va_list* pap) throw (err_format_exception) { - const char** l_fmt = &fmt; - va_list ap; - va_start(ap, fmt); - //BOOST_SCOPE_EXIT( (&ap) ) { va_end(ap); } BOOST_SCOPE_EXIT_END; try { - eterm res( eformat(l_fmt, &ap, a_alloc) ); - va_end(ap); - return res; + return eformat(fmt, pap, a_alloc); } catch (err_format_exception& e) { - va_end(ap); - e.start(*l_fmt); + e.start(*fmt); throw; + } catch (...) { + throw err_format_exception("Error parsing expression", *fmt, *fmt); } } template -eterm eterm::format(const char* fmt, ...) - throw (err_format_exception) +void eterm::format(const Alloc& a_alloc, atom& m, atom& f, eterm& args, + const char** fmt, va_list* pap) throw (err_format_exception) { - const char** l_fmt = &fmt; - va_list ap; - va_start(ap, fmt); - //BOOST_SCOPE_EXIT( (&ap) ) { va_end(ap); } BOOST_SCOPE_EXIT_END; try { - Alloc alloc; - eterm res = eformat(l_fmt, &ap, alloc); - va_end(ap); - return res; + eformat(m, f, args, fmt, pap, a_alloc); } catch (err_format_exception& e) { - va_end(ap); - e.start(*l_fmt); + e.start(*fmt); throw; + } catch (...) { + throw err_format_exception("Error parsing expression", *fmt, *fmt); } } +template +eterm eterm::format(const Alloc& a_alloc, const char* fmt, ...) + throw (err_format_exception) +{ + va_list ap; + va_start(ap, fmt); + try { return format(a_alloc, &fmt, &ap); } catch (...) { va_end(ap); throw; } + va_end(ap); +} + +template +eterm eterm::format(const char* fmt, ...) + throw (err_format_exception) +{ + va_list ap; + va_start(ap, fmt); + try { return format(Alloc(), &fmt, &ap); } catch (...) { va_end(ap); throw; } + va_end(ap); +} + +template +void eterm::format(const Alloc& a_alloc, atom& m, atom& f, eterm& args, + const char* fmt, ...) throw (err_format_exception) +{ + va_list ap; + va_start(ap, fmt); + try { format(a_alloc, m, f, args, &fmt, &ap); } catch (...) { va_end(ap); throw; } + va_end(ap); +} +template +void eterm::format(atom& m, atom& f, eterm& args, const char* fmt, ...) + throw (err_format_exception) +{ + va_list ap; + va_start(ap, fmt); + try { format(Alloc(), m, f, args, &fmt, &ap); } catch (...) { va_end(ap); throw; } + va_end(ap); +} + } // namespace marshal } // namespace EIXX_NAMESPACE diff --git a/include/eixx/marshal/eterm_format.hpp b/include/eixx/marshal/eterm_format.hpp index 3a67980..a9d8eec 100644 --- a/include/eixx/marshal/eterm_format.hpp +++ b/include/eixx/marshal/eterm_format.hpp @@ -56,6 +56,14 @@ template static eterm eformat(const char** fmt, va_list* args, const Alloc& a_alloc = Alloc()) throw(err_format_exception); +/** + * Parse a format string in the form "Module:Function(Args...)" into corresponding + * \a mod, \a fun, \a args + */ +template +static void eformat(atom& mod, atom& fun, eterm& args, + const char** fmt, va_list* pa, const Alloc& a_alloc = Alloc()); + } // namespace marshal } // namespace EIXX_NAMESPACE diff --git a/include/eixx/marshal/eterm_format.ipp b/include/eixx/marshal/eterm_format.ipp index 1e515d6..3ca690d 100644 --- a/include/eixx/marshal/eterm_format.ipp +++ b/include/eixx/marshal/eterm_format.ipp @@ -49,24 +49,45 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include +#include +#include //#include namespace EIXX_NAMESPACE { namespace marshal { - template - struct vector : public std::vector, Alloc> { - explicit vector(const Alloc& a_alloc = Alloc()) - : std::vector, Alloc> (a_alloc) - {} - }; + namespace { - enum { - ERL_OK = 0 - , ERL_FMT_ERR = -1 - , ERL_MAX_ENTRIES = 255 /* Max entries in a tuple/list term */ - , ERL_MAX_NAME_LENGTH = 255 /* Max length of variable names */ - }; + template + struct vector : public std::vector, Alloc> { + typedef std::vector, Alloc> base; + + explicit vector(const Alloc& a_alloc = Alloc()) : base(a_alloc) + {} + + eterm to_tuple(Alloc& a_alloc) { + eterm& term = (eterm&)*this->begin(); + auto t = tuple(&term, this->size(), a_alloc); + return eterm(t); + } + + eterm to_list(Alloc& a_alloc) { + eterm& term = (eterm&)*this->begin(); + auto t = list(&term, this->size(), a_alloc); + return eterm(t); + } + + const eterm& operator[] (size_t idx) const { + return (const eterm&)*(base::begin()+idx); + } + + const eterm& back() const { + return (const eterm&)*(base::end()-1); + } + }; + + } // namespace static void skip_ws_and_comments(const char** fmt) { bool inside_comment = false; @@ -124,111 +145,90 @@ namespace marshal { } /* pvariable */ - static char *patom(const char **fmt, char *buf) + static atom patom(const char **fmt) { - const char* start = *fmt; - char c; - int len; - skip_ws_and_comments(fmt); - while (1) { - c = *(*fmt)++; - if (isalnum((int) c) || (c == '_') || (c == '@')) - continue; - else - break; - } - (*fmt)--; - len = *fmt - start; - memcpy(buf, start, len); - buf[len] = 0; + const char* start = *fmt, *p = start; - return buf; + for(char c = *p; c && (isalnum(c) || c == '_' || c == '@'); c = *(++p)); + + *fmt = p; + return atom(start, p - start); } /* patom */ + static atom pquotedatom(const char **fmt) + { + ++(*fmt); /* skip first quote */ + //skip_ws_and_comments(fmt); + + const char* start = *fmt, *p = start; + + for (char c = *p; c && (c != '\'' || *(p-1) == '\\') ; c = *(++p)); + + if (*p != '\'') + throw err_format_exception("Error parsing quotted atom", start); + + *fmt = p+1; /* skip last quote */ + int len = p - start; + + return atom(start, len); + + } /* pquotedatom */ + /* Check if integer or float */ - static char *pdigit(const char **fmt, char *buf) + template + static eterm pdigit(const char **fmt) { - const char* start = *fmt; - char c; - int len,dotp=0; + const char* start = *fmt, *p = start; + bool dotp = false; + int base = 10; skip_ws_and_comments(fmt); - while (1) { - c = *(*fmt)++; - if (isdigit((int) c) || c == '-') - continue; - else if (!dotp && (c == '.')) { - dotp = 1; + if (*p == '-') p++; + + for (char c = *p; c; c = *(++p)) { + if (isdigit(c)) continue; - } - else + else if (c == '.' && !dotp) + dotp = true; + else if (c == '#') { + base = strtol(start, NULL, 10); + start = p+1; + } else break; } - (*fmt)--; - len = *fmt - start; - memcpy(buf, start, len); - buf[len] = 0; - - return buf; + *fmt = p; + if (dotp) { + auto d = strtod(start, NULL); + return d; + } + auto n = strtol(start, NULL, base); + return n; } /* pdigit */ - static char *pstring(const char **fmt, char *buf) + template + static eterm pstring(const char **fmt, Alloc& alloc) { const char* start = ++(*fmt); /* skip first quote */ - char c; - int len; + const char* p = start; // skip_ws_and_comments(fmt); - while (1) { - c = *(*fmt)++; - if (c == '"') { - if (*((*fmt)-1) == '\\') - continue; - else - break; - } else - continue; - } - len = *fmt - 1 - start; /* skip last quote */ - memcpy(buf, start, len); - buf[len] = 0; - - return buf; - - } /* pstring */ - - static char *pquotedatom(const char **fmt, char *buf) - { - const char* start = ++(*fmt); /* skip first quote */ - char c; - int len; + for (char c = *p; c && (c != '"' || *(p-1) == '\\'); c = *(++p)); - skip_ws_and_comments(fmt); + if (*p != '"') + throw err_format_exception("Error parsing string", start); - while (1) { - c = *(*fmt)++; - if (c == '\'') { - if (*((*fmt)-1) == '\\') - continue; - else - break; - } else - continue; - } - len = *fmt - 1 - start; /* skip last quote */ - memcpy(buf, start, len); - buf[len] = 0; + *fmt = p+1; /* skip last quote */ + int len = p - start; - return buf; - - } /* pquotedatom */ + return eterm(string(start, len, alloc)); + } /* pstring */ /// @todo Implement support for parsing tail list expressions in the form @@ -244,64 +244,34 @@ namespace marshal { * w - A pointer to some arbitrary term */ template - static int pformat(const char** fmt, va_list* pap, - vector& v, Alloc& a_alloc) + static eterm pformat(const char** fmt, va_list* pap, Alloc& a_alloc) { - int rc=ERL_OK; - - /* this next section hacked to remove the va_arg calls */ skip_ws_and_comments(fmt); switch (*(*fmt)++) { - case 'w': - v.push_back(*va_arg(*pap, eterm*)); - break; - - case 'a': - v.push_back(eterm(atom(va_arg(*pap, char*)))); - break; - - case 's': - v.push_back(eterm(string(va_arg(*pap, char*), a_alloc))); - break; - - case 'i': - v.push_back(eterm(va_arg(*pap, int))); - break; - - case 'l': - v.push_back(eterm(va_arg(*pap, long))); - break; - - case 'u': - v.push_back(eterm((long)va_arg(*pap, unsigned long))); - break; - - case 'f': - v.push_back(eterm(va_arg(*pap, double))); - break; - - default: - rc = ERL_FMT_ERR; - break; + case 'w': return *va_arg(*pap, eterm*); + case 'a': return atom(va_arg(*pap, char*)); + case 's': return string(va_arg(*pap, char*), a_alloc); + case 'i': return va_arg(*pap, int); + case 'l': return va_arg(*pap, long); + case 'u': return (long)va_arg(*pap, unsigned long); + case 'f': return va_arg(*pap, double); + default: throw err_format_exception("Error parsing string", *fmt-1); } - - return rc; - } /* pformat */ template - static int ptuple(const char** fmt, va_list* pap, + static bool ptuple(const char** fmt, va_list* pap, vector& v, Alloc& a_alloc) { - int res=ERL_FMT_ERR; + bool res = false; skip_ws_and_comments(fmt); switch (*(*fmt)++) { case '}': - res = ERL_OK; + res = true; break; case ',': @@ -314,16 +284,6 @@ namespace marshal { if (v.back().type() != UNDEFINED) res = ptuple(fmt, pap, v, a_alloc); break; - - /* - if (isupper(**fmt)) { - v[size++] = erl_mk_var(pvariable(fmt, wbuf)); - res = ptuple(fmt, pap, v); - } - else if ((v[size++] = eformat(fmt, pap)) != (ErlTerm *) NULL) - res = ptuple(fmt, pap, v); - break; - */ } } /* switch */ @@ -333,17 +293,17 @@ namespace marshal { } /* ptuple */ template - static int plist(const char** fmt, va_list* pap, + static bool plist(const char** fmt, va_list* pap, vector& v, Alloc& a_alloc) { - int res=ERL_FMT_ERR; + bool res = false; skip_ws_and_comments(fmt); switch (*(*fmt)++) { case ']': - res = ERL_OK; + res = true; break; case ',': @@ -357,14 +317,14 @@ namespace marshal { v.push_back(eterm(a)); skip_ws_and_comments(fmt); if (**fmt == ']') - res = ERL_OK; + res = true; break; } break; default: { (*fmt)--; - eterm et = eformat(fmt, pap, a_alloc); + auto et = eformat(fmt, pap, a_alloc); if (et.type() != UNDEFINED) { v.push_back(et); res = plist(fmt, pap, v, a_alloc); @@ -389,58 +349,43 @@ namespace marshal { skip_ws_and_comments(fmt); switch (*(*fmt)++) { - case '{': - if (ptuple(fmt, pap, v, alloc) != ERL_OK) + case '{': { + if (!ptuple(fmt, pap, v, alloc)) throw err_format_exception("Error parsing tuple", *fmt); - ret.set( eterm(tuple(&v[0], v.size(), alloc)) ); + ret = v.to_tuple(alloc); break; - + } case '[': if (**fmt == ']') { (*fmt)++; - ret.set( eterm(list(0, alloc)) ); - } else if (plist(fmt, pap, v, alloc) == ERL_OK) { - ret.set( eterm(list(&v[0], v.size(), alloc)) ); - } else { + ret = v.to_list(alloc); + } else if (!plist(fmt, pap, v, alloc)) throw err_format_exception("Error parsing list", *fmt); - } + ret = v.to_list(alloc); break; case '$': /* char-value? */ - ret.set( eterm((int)(*(*fmt)++)) ); + ret = eterm((int)(*(*fmt)++)); break; case '~': - if (pformat(fmt, pap, v, alloc) != ERL_OK) - throw err_format_exception("Error parsing term", *fmt); - ret.set(v[0]); + ret = pformat(fmt, pap, alloc); break; default: { - char wbuf[BUFSIZ]; /* now local to this function for reentrancy */ - (*fmt)--; - if (islower((int)**fmt)) { /* atom ? */ - char* a = patom(fmt, wbuf); - ret.set( eterm(atom(a)) ); - } else if (isupper((int)**fmt) || (**fmt == '_')) { - var v = pvariable(fmt); - ret.set( eterm(v) ); - } else if (isdigit((int)**fmt) || **fmt == '-') { /* integer/float ? */ - char* digit = pdigit(fmt, wbuf); - if (strchr(digit,(int) '.') == NULL) - ret.set( eterm(atoi((const char *) digit)) ); - else - ret.set( eterm(atof((const char *) digit)) ); - } else if (**fmt == '"') { /* string ? */ - char* str = pstring(fmt, wbuf); - ret.set( eterm(string(str, alloc)) ); - } else if (**fmt == '\'') { /* quoted atom ? */ - char* qatom = pquotedatom(fmt, wbuf); - ret.set( eterm(atom(qatom)) ); - } + if (islower(**fmt)) /* atom ? */ + ret = patom(fmt); + else if (isupper(**fmt) || (**fmt == '_')) + ret = pvariable(fmt); + else if (isdigit(**fmt) || **fmt == '-') /* int|float ? */ + ret = pdigit(fmt); + else if (**fmt == '"') /* string ? */ + ret = pstring(fmt, alloc); + else if (**fmt == '\'') /* quoted atom ? */ + ret = pquotedatom(fmt); + break; } - break; } if (ret.empty()) @@ -450,6 +395,67 @@ namespace marshal { } /* eformat */ + template + static void eformat(atom& mod, atom& fun, eterm& args, + const char** fmt, va_list* pap, const Alloc& a_alloc = Alloc()) + { + Alloc alloc(a_alloc); + vector v(alloc); + + skip_ws_and_comments(fmt); + + const char* start = *fmt, *p = start; + const char* q = strchr(p, ':'); + + if (!q) + throw err_format_exception("Module name not found", p); + + mod = atom(p, q - p); + + p = q+1; + + q = strchr(p, '('); + + if (!q) + throw err_format_exception("Function name not found", p); + + fun = atom(p, q - p); + + p = q+1; + + skip_ws_and_comments(&p); + + if (*p == '\0') + throw err_format_exception("Invalid argument syntax", p); + else if (*p == ')') + ++p; + else while(true) { + v.push_back(eformat(&p, pap, a_alloc)); + skip_ws_and_comments(&p); + + char c = *p++; + + if (c == '\0') + throw err_format_exception("Arguments list not closed", &c); + else if (c == ')') + break; + if (c != ',') + throw err_format_exception("Arguments must be comma-delimited", &c); + } + + skip_ws_and_comments(&p); + + if (*p != '\0') { + if (*p == '.') { + ++p; skip_ws_and_comments(&p); + } + } + + if (*p != '\0') + throw err_format_exception("Invalid MFA format", p); + + args = v.to_list(alloc); + } } // namespace marshal } // namespace EIXX_NAMESPACE diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index 311ebd2..995c3df 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -183,10 +183,7 @@ class eterm_pattern_matcher { varbind* a_binding = NULL) const { bool res = false; - for(typename std::list, Alloc>::const_iterator - it = m_pattern_list.begin(), end = m_pattern_list.end(); - it != end; ++it) - { + for(auto it = m_pattern_list.begin(), end = m_pattern_list.end(); it != end; ++it) { if (it->operator() (a_term, a_binding)) { res = true; break; diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index b85ee9d..f2e1a80 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include namespace EIXX_NAMESPACE { namespace marshal { @@ -105,7 +106,7 @@ class list : protected alloc_base, Alloc> { iterator begin() { iterator it(empty() ? NULL : head()); return it; } iterator end() { return iterator::end(); } - + const_iterator begin() const { const_iterator it(empty() ? NULL : head()); return it; } const_iterator end() const { return iterator::end(); } @@ -125,20 +126,27 @@ class list : protected alloc_base, Alloc> { l_header->tail = NULL; } - list(const list& a) - : base_t(a.get_allocator()), m_blob(a.m_blob) - { + list(const list& a) : base_t(a.get_allocator()), m_blob(a.m_blob) { BOOST_ASSERT(a.initialized()); if (m_blob) m_blob->inc_rc(); } + list(list&& a) : base_t(a.get_allocator()), m_blob(a.m_blob) { + a.m_blob = nullptr; + } + explicit list(const cons_t* a_head, int a_len = -1, const Alloc& alloc = Alloc()) throw (err_bad_argument); template - list(const eterm (&items)[N], const Alloc& alloc = Alloc()); + list(const eterm (&items)[N], const Alloc& alloc = Alloc()) + : list(items, N, alloc) {} + + list(const eterm* items, size_t a_size, const Alloc& alloc = Alloc()) + : base_t(alloc) { init(items, a_size, alloc); } - list(const eterm items[], size_t a_size, const Alloc& alloc = Alloc()); + list(std::initializer_list> items, const Alloc& alloc = Alloc()) + : list(items.begin(), items.size(), alloc) {} /** * Decode the list from a binary buffer. @@ -186,6 +194,14 @@ class list : protected alloc_base, Alloc> { list tail(size_t idx) const throw(err_bad_argument); + list& operator= (const list& rhs) { + BOOST_ASSERT(rhs.initialized()); + release(); + m_blob = rhs.m_blob; + if (m_blob) m_blob->inc_rc(); + return *this; + } + bool operator== (const list& rhs) const { const_iterator it1 = begin(), it2 = rhs.begin(), end1 = end(), end2 = rhs.end(); @@ -216,7 +232,7 @@ class list : protected alloc_base, Alloc> { bool match(const eterm& pattern, varbind* binding) const throw (err_invalid_term, err_unbound_variable); - + std::ostream& dump(std::ostream& out, const varbind* vars = NULL) const; static list make(const Alloc& a = Alloc()) { diff --git a/include/eixx/marshal/list.ipp b/include/eixx/marshal/list.ipp index 716cbb4..f08f439 100644 --- a/include/eixx/marshal/list.ipp +++ b/include/eixx/marshal/list.ipp @@ -41,20 +41,7 @@ namespace EIXX_NAMESPACE { namespace marshal { template -template -inline list::list(const eterm (&items)[N], const Alloc& alloc) - : base_t(alloc) { - init(items, N, alloc); -} - -template -inline list::list(const eterm items[], size_t N, const Alloc& alloc) - : base_t(alloc) { - init(items, N, alloc); -} - -template -void list::init(const eterm items[], size_t N, const Alloc& alloc) { +void list::init(const eterm* items, size_t N, const Alloc& alloc) { size_t n = N > 0 ? N : 1; m_blob = new blob_t(sizeof(header_t) + n*sizeof(cons_t), alloc); @@ -65,17 +52,17 @@ void list::init(const eterm items[], size_t N, const Alloc& alloc) l_header->alloc_size = n; l_header->size = N; - for (size_t i=0; i < N; i++) { - BOOST_ASSERT(items[i].initialized()); - new (&hd[i].node) eterm(items[i]); - hd[i].next = &hd[i+1]; + for(auto p = items, *end = items+N; p != end; ++p, ++hd) { + BOOST_ASSERT(p->initialized()); + new (&hd->node) eterm(*p); + hd->next = hd+1; } if (N == 0) l_header->tail = NULL; else { - l_header->tail = &hd[n-1]; - hd[N-1].next = NULL; + l_header->tail = hd-1; + l_header->tail->next = NULL; } } @@ -127,15 +114,15 @@ list::list(const char *buf, int& idx, size_t size, const Alloc& a_alloc) l_header->size = arity; cons_t* hd = l_header->head; - for (int i=0; i < arity; i++) { + for (cons_t* end = hd+arity; hd != end; ++hd) { eterm et(buf, idx, size, a_alloc); - new (&hd[i].node) eterm(et); - hd[i].next = &hd[i+1]; + new (&hd->node) eterm(et); + hd->next = hd+1; } if (arity == 0) { l_header->tail = NULL; } else { - l_header->tail = &hd[arity-1]; + l_header->tail = hd-1; l_header->tail->next = NULL; if (*(buf+idx) != ERL_NIL_EXT) throw err_decode_exception("Not a NIL list!", idx); diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index 92cebc2..f7cb615 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -72,6 +72,8 @@ class epid { {} }; + BOOST_STATIC_ASSERT(sizeof(pid_blob) == sizeof(void*)); + blob* m_blob; void release() { @@ -100,10 +102,12 @@ class epid { void decode(const char* buf, int& idx, size_t size, const Alloc& a_alloc) throw (err_decode_exception, err_bad_argument); - epid() {} - public: + static const epid null; + + epid() : m_blob(nullptr) {} + /** * Create an Erlang pid from its components using provided allocator. * @param node the nodename. @@ -139,50 +143,63 @@ class epid { } epid(const epid& rhs) : m_blob(rhs.m_blob) { - m_blob->inc_rc(); - #ifdef EIXX_DEBUG - std::cerr << "Copied pid " << *this - << " [addr=" << this << ", blob=" << m_blob - << ", rc=" << m_blob->use_count() << ']' << std::endl; - #endif + if (m_blob) { + m_blob->inc_rc(); + #ifdef EIXX_DEBUG + std::cerr << "Copied pid " << *this + << " [addr=" << this << ", blob=" << m_blob + << ", rc=" << m_blob->use_count() << ']' << std::endl; + #endif + } } + epid(epid&& rhs) : m_blob(rhs.m_blob) { rhs.m_blob = nullptr; } + ~epid() { release(); } - void operator= (const epid& rhs) { - release(); m_blob = rhs.m_blob; m_blob->inc_rc(); - #ifdef EIXX_DEBUG - std::cerr << "Copied pid " << *this - << " [addr=" << this << ", blob=" << m_blob - << ", rc=" << m_blob->use_count() << ']' << std::endl; - #endif + epid& operator= (const epid& rhs) { + if (this != &rhs) { + release(); + m_blob = rhs.m_blob; + if (!m_blob) m_blob->inc_rc(); + } + return *this; + } + + epid& operator= (epid&& rhs) { + if (this != &rhs) { + release(); + m_blob = rhs.m_blob; + rhs.m_blob = nullptr; + } + return *this; } /** * Get the node name from the PID. * @return the node name from the PID. **/ - const atom& node() const { return m_blob->data()->node; } + atom node() const { return m_blob ? m_blob->data()->node : atom::null; } /** * Get the id number from the PID. * @return the id number from the PID. **/ - int id() const { return m_blob->data()->u.s.id; } + int id() const { return m_blob ? m_blob->data()->u.s.id : 0; } /** * Get the serial number from the PID. * @return the serial number from the PID. **/ - int serial() const { return m_blob->data()->u.s.serial; } + int serial() const { return m_blob ? m_blob->data()->u.s.serial : 0; } /** * Get the creation number from the PID. * @return the creation number from the PID. **/ - int creation() const { return m_blob->data()->u.s.creation; } + int creation() const { return m_blob ? m_blob->data()->u.s.creation : 0; } - uint32_t id_internal() const { return m_blob->data()->u.i & 0x7FFFFFFF; } + uint32_t id_internal() const { return m_blob ? m_blob->data()->u.i & 0x7FFFFFFF : 0; } bool operator== (const epid& rhs) const { return id_internal() == rhs.id_internal() && node() == rhs.node(); diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index eae3188..e88db21 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -73,8 +73,11 @@ class port { new (m_blob->data()) port_blob(node, id & 0x0fffffff, creation & 0x03); } - port() {} public: + static const port null; + + port() : m_blob(nullptr) {} + /** * Create an Erlang port from its components. * If node string size is greater than MAX_NODE_LENGTH or = 0, @@ -113,29 +116,43 @@ class port { port(const char *buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) throw (err_decode_exception); - port(const port& rhs) : m_blob(rhs.m_blob) { m_blob->inc_rc(); } + port(const port& rhs) : m_blob(rhs.m_blob) { if (m_blob) m_blob->inc_rc(); } + port(port&& rhs) : m_blob(rhs.m_blob) { rhs.m_blob = nullptr; } ~port() { release(); } - void operator= (const port& rhs) { release(); m_blob = rhs.m_blob; m_blob->inc_rc(); } + port& operator= (const port& rhs) { + if (this != &rhs) { + release(); m_blob = rhs.m_blob; + if (m_blob) m_blob->inc_rc(); + } + return *this; + } + + port& operator= (port&& rhs) { + if (this != &rhs) { + release(); m_blob = rhs.m_blob; rhs.m_blob = nullptr; + } + return *this; + } /** * Get the node name from the PORT. * @return the node name from the PORT. **/ - const atom& node() const { return m_blob->data()->node; } + atom node() const { return m_blob ? m_blob->data()->node : atom::null; } /** * Get the id number from the PORT. * @return the id number from the PORT. **/ - int id() const { return m_blob->data()->id; } + int id() const { return m_blob ? m_blob->data()->id : 0; } /** * Get the creation number from the PORT. * @return the creation number from the PORT. **/ - int creation() const { return m_blob->data()->creation; } + int creation() const { return m_blob ? m_blob->data()->creation : 0; } bool operator== (const port& t) const { return id() == t.id() && node() == t.node() && creation() == t.creation(); diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index d411792..c8e6ef0 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -39,6 +39,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace EIXX_NAMESPACE { namespace marshal { +namespace detail { + extern const uint32_t s_ref_ids[3]; +} // namespace detail /** * Representation of erlang Pids. @@ -77,8 +80,11 @@ class ref { m_blob->release(); } - ref() {} public: + static const ref null; + + ref() : m_blob(nullptr) {} + /** * Create an Erlang ref from its components. * If node string size is greater than MAX_NODE_LENGTH or = 0, @@ -128,17 +134,31 @@ class ref { ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) throw(err_decode_exception); - ref(const ref& rhs) : m_blob(rhs.m_blob) { m_blob->inc_rc(); } + ref(const ref& rhs) : m_blob(rhs.m_blob) { if (m_blob) m_blob->inc_rc(); } + ref(ref&& rhs) : m_blob(rhs.m_blob) { rhs.m_blob = nullptr; } ~ref() { release(); } - void operator= (const ref& rhs) { release(); m_blob = rhs.m_blob; m_blob->inc_rc(); } + ref& operator= (const ref& rhs) { + if (this != &rhs) { + release(); m_blob = rhs.m_blob; + if (m_blob) m_blob->inc_rc(); + } + return *this; + } + + ref& operator= (ref&& rhs) { + if (this != &rhs) { + release(); m_blob = rhs.m_blob; rhs.m_blob = nullptr; + } + return *this; + } /** * Get the node name from the REF. * @return the node name from the REF. */ - const atom& node() const { return m_blob->data()->node; } + atom node() const { return m_blob ? m_blob->data()->node : atom::null; } /** * Get an id number from the REF. @@ -154,17 +174,17 @@ class ref { * Get the id array from the REF. * @return the id array number from the REF. */ - const uint32_t* ids() const { return m_blob->data()->ids; } + const uint32_t* ids() const { return m_blob ? m_blob->data()->ids : detail::s_ref_ids; } /** * Get the creation number from the REF. * @return the creation number from the REF. */ - int creation() const { return m_blob->data()->creation; } + int creation() const { return m_blob ? m_blob->data()->creation : 0; } bool operator==(const ref& t) const { return node() == t.node() && - memcmp(ids(), t.ids(), COUNT*sizeof(uint32_t)) == 0 && + ::memcmp(ids(), t.ids(), COUNT*sizeof(uint32_t)) == 0 && creation() == t.creation(); } @@ -187,7 +207,7 @@ class ref { void encode(char* buf, int& idx, size_t size) const; - std::ostream& dump(std::ostream& out, const varbind* binding=NULL) const { + std::ostream& dump(std::ostream& out, const varbind* binding=nullptr) const { return out << *this; } }; diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index 7a19372..36ab794 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -60,12 +60,12 @@ class string public: typedef const char* const_iterator; - string() : m_blob(NULL) {} + string() : m_blob(nullptr) {} string(const char* s, const Alloc& a = Alloc()) { BOOST_ASSERT(s); if (!s[0]) { - m_blob = NULL; + m_blob = nullptr; return; } m_blob = new blob(strlen(s)+1, a); @@ -74,7 +74,7 @@ class string } string(const std::string& s, const Alloc& a = Alloc()) { if (s.empty()) { - m_blob = NULL; + m_blob = nullptr; return; } m_blob = new blob(s.size()+1, a); @@ -83,7 +83,7 @@ class string } string(const char* s, size_t n, const Alloc& a = Alloc()) { if (n == 0) { - m_blob = NULL; + m_blob = nullptr; return; } m_blob = new blob(n+1, a); @@ -94,6 +94,10 @@ class string if (m_blob) m_blob->inc_rc(); } + string(string&& s) : m_blob(s.m_blob) { + s.m_blob = nullptr; + } + string(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) throw(err_decode_exception); @@ -101,10 +105,22 @@ class string release(); } - void operator= (const string& s) { - release(); - m_blob = s.m_blob; - if (m_blob) m_blob->inc_rc(); + string& operator= (const string& s) { + if (this != &s) { + release(); + m_blob = s.m_blob; + if (m_blob) m_blob->inc_rc(); + } + return *this; + } + + string& operator= (string&& s) { + if (this != &s) { + release(); + m_blob = s.m_blob; + s.m_blob = nullptr; + } + return *this; } void operator= (const std::string& s) { diff --git a/include/eixx/marshal/tuple.hpp b/include/eixx/marshal/tuple.hpp index 9f63d37..13f12df 100644 --- a/include/eixx/marshal/tuple.hpp +++ b/include/eixx/marshal/tuple.hpp @@ -34,6 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define _IMPL_TUPLE_HPP_ #include +#include #include #include #include @@ -61,6 +62,16 @@ class tuple { return m_blob->data()[m_blob->size()-1].to_long()-1; } + void release() { release(m_blob); m_blob = nullptr; } + + void release(blob, Alloc>* p) { + if (p && p->release(false)) { + for(size_t i=0, n=size(); i < n; i++) + p->data()[i].~eterm(); + p->free(); + } + } + protected: template void init_element(size_t i, const V& v) { @@ -88,12 +99,15 @@ class tuple { m_blob->inc_rc(); } - template - tuple(const eterm (&items)[N], const Alloc& alloc = Alloc()) { - new (this) tuple(items, N, alloc); + tuple(tuple&& a) : m_blob(a.m_blob) { + a.m_blob = nullptr; } - tuple(const eterm items[], size_t a_size, const Alloc& alloc = Alloc()) + template + tuple(const eterm (&items)[N], const Alloc& alloc = Alloc()) + : tuple(items, N, alloc) {} + + tuple(const eterm* items, size_t a_size, const Alloc& alloc = Alloc()) : m_blob(new blob, Alloc>(a_size+1, alloc)) { for(size_t i=0; i < a_size; i++) { new (&m_blob->data()[i]) eterm(items[i]); @@ -101,6 +115,9 @@ class tuple { set_init_size(a_size); } + tuple(std::initializer_list> list, const Alloc& alloc = Alloc()) + : tuple(list.begin(), list.size(), alloc) {} + /** * Decode the tuple from a binary buffer. */ @@ -108,19 +125,25 @@ class tuple { throw(err_decode_exception); ~tuple() { - if (m_blob && m_blob->release(false)) { - for(size_t i=0, n=size(); i < n; i++) - m_blob->data()[i].~eterm(); - m_blob->free(); - } + release(); } tuple& operator= (const tuple& rhs) { if (this != &rhs) { - blob, Alloc>* p = m_blob; + auto p = m_blob; m_blob = rhs.m_blob; - m_blob->inc_rc(); - if (p) p->release(); + if (m_blob) m_blob->inc_rc(); + release(p); + } + return *this; + } + + tuple& operator= (tuple&& rhs) { + if (this != &rhs) { + auto p = m_blob; + m_blob = rhs.m_blob; + rhs.m_blob = nullptr; + release(p); } return *this; } @@ -181,7 +204,7 @@ class tuple { bool match(const eterm& pattern, varbind* binding) const throw (err_invalid_term, err_unbound_variable); - + std::ostream& dump(std::ostream& out, const varbind* vars = NULL) const; template diff --git a/include/eixx/marshal/var.hpp b/include/eixx/marshal/var.hpp index e33a91f..6d64f9d 100644 --- a/include/eixx/marshal/var.hpp +++ b/include/eixx/marshal/var.hpp @@ -51,27 +51,27 @@ namespace marshal { **/ class var { - uint32_t m_type; - atom m_name; + atom m_name; + int m_type; - bool check_type(eterm_type t) const { return is_any() || t == type(); } + bool check_type(eterm_type t) const { + return is_any() || m_type == UNDEFINED || t == m_type; + } typedef util::atom_table<>::string_t string_t; + + eterm_type set(eterm_type t) { return m_name == am_ANY_ ? UNDEFINED : t; } + public: - var(eterm_type t = UNDEFINED) - { m_type = t; m_name = am_ANY_; } - var(const char* s, eterm_type t = UNDEFINED) - { m_type = t; m_name = atom(s); } - var(const std::string& s, eterm_type t = UNDEFINED) - { m_type = t; m_name = atom(s); } + var(eterm_type t = UNDEFINED) : var(am_ANY_, t) {} + var(const atom& s, eterm_type t = UNDEFINED) : m_name(s) { m_type = set(t); } + + var(const char* s, eterm_type t = UNDEFINED) : var(atom(s), t) {} + var(const std::string& s, eterm_type t = UNDEFINED) : var(atom(s), t) {} template - var(const string& s, eterm_type t = UNDEFINED) - { m_type = t; m_name = atom(s); } - var(const char* s, size_t n, eterm_type t = UNDEFINED) - { m_type = t; m_name = atom(s, n); } - var(const atom& s, eterm_type t = UNDEFINED) - { m_type = t; m_name = s; } - var(const var& v) { m_type = v.m_type; m_name = v.m_name; } + var(const string& s, eterm_type t = UNDEFINED) : var(atom(s), t) {} + var(const char* s, size_t n, eterm_type t = UNDEFINED) : var(atom(s, n), t) {} + var(const var& v) : var(v.name(), v.type()) {} const char* c_str() const { return m_name.c_str(); } const string_t& str() const { return m_name.to_string(); } @@ -94,7 +94,7 @@ class var void encode(char* buf, int& idx, size_t size) const { throw err_encode_exception("Cannot encode vars!"); - } + } template const eterm* @@ -117,8 +117,9 @@ class var bool match(const eterm& pattern, varbind* binding) const throw (err_unbound_variable) { + if (is_any()) return true; if (!binding) return false; - const eterm* value = binding ? binding->find(name()) : NULL; + const eterm* value = binding->find(name()); if (value) return check_type(value->type()) ? value->match(pattern, binding) : false; if (!check_type(pattern.type())) diff --git a/include/eixx/util/async_wait_timeout.hpp b/include/eixx/util/async_wait_timeout.hpp index d5ba169..4ed529b 100644 --- a/include/eixx/util/async_wait_timeout.hpp +++ b/include/eixx/util/async_wait_timeout.hpp @@ -15,12 +15,12 @@ namespace error { namespace detail { struct timer_category : public boost::system::error_category { - const char* name() const { return "asio.timer"; } + const char* name() const noexcept { return "asio.timer"; } std::string message(int value) const { - if (value == error::timeout) - return "Operation timed out"; - return "asio.timer error"; + return value == error::timeout + ? "Operation timed out" + : "asio.timer error"; } }; @@ -31,8 +31,13 @@ namespace error { return instance; } - static const boost::system::error_category& timer_category - = boost::asio::error::get_timer_category(); +// static const boost::system::error_category& timer_category +// = boost::asio::error::get_timer_category(); + + inline boost::system::error_code make_error_code(boost::asio::error::timer_errors e) { + return boost::system::error_code( + static_cast(e), boost::asio::error::get_timer_category()); + } } // namespace error } // namespace asio @@ -43,13 +48,10 @@ namespace system { static const bool value = true; }; - inline boost::system::error_code make_error_code(boost::asio::error::timer_errors e) { - return boost::system::error_code( - static_cast(e), boost::asio::error::get_timer_category()); - } - } // namespace system +#include + namespace asio { class deadline_timer_ex : public basic_deadline_timer @@ -64,7 +66,7 @@ namespace asio { //if (ec == error::operation_aborted) // return; system::error_code e = ec == system::error_code() - ? system::make_error_code(error::timeout) + ? make_error_code(error::timeout) : ec; m_h(e); } diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 73b0a1b..42dbe52 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -150,7 +150,7 @@ namespace util { } /// Lookup an atom in the atom table by index. - const string_t& lookup(size_t n) const { return (*this)[n]; } + const string_t& get(int n) const { return (*this)[n]; } /// Lookup an atom in the atom table by index. const string_t& operator[] (int n) const { @@ -163,30 +163,30 @@ namespace util { /// atom in the atom table. /// @throws std::runtime_error if atom table is full. /// @throws err_bad_argument if atom size is longer than MAXATOMLEN - int lookup(const char* a_atom, size_t n) { return lookup(std::string(a_atom, n)); } - int lookup(const char* a_atom) { return lookup(std::string(a_atom)); } - int lookup(const std::string& a_atom) + int lookup(const char* a_name, size_t n) { return lookup(std::string(a_name, n)); } + int lookup(const char* a_name) { return lookup(std::string(a_name)); } + int lookup(const std::string& a_name) throw(std::runtime_error, err_bad_argument) { - if (a_atom.size() == 0) + if (a_name.size() == 0) return 0; - if (a_atom.size() > MAXATOMLEN) + if (a_name.size() > MAXATOMLEN) throw err_bad_argument("Atom size is too long!"); - size_t bucket = m_index.bucket(a_atom.c_str()); - int n = find_value(bucket, a_atom.c_str()); + size_t bucket = m_index.bucket(a_name.c_str()); + int n = find_value(bucket, a_name.c_str()); if (n >= 0) return n; lock_guard guard(m_lock); - n = find_value(bucket, a_atom.c_str()); + n = find_value(bucket, a_name.c_str()); if (n >= 0) return n; n = m_atoms.size(); if ((size_t)(n+1) == m_atoms.capacity()) throw std::runtime_error("Atom hash table is full!"); - m_atoms.push_back(a_atom); - m_index[a_atom.c_str()] = n; + m_atoms.push_back(a_name); + m_index[a_name.c_str()] = n; return n; } private: diff --git a/src/Makefile.am b/src/Makefile.am index 4fdeb19..ba649b2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -76,7 +76,8 @@ libeixx_la_hdr3_HEADERS = $(eixx_hdrs3:%=../include/@PACKAGE@/%) libeixx_la_hdr4dir = $(includedir)/@PACKAGE@/util libeixx_la_hdr4_HEADERS = $(eixx_hdrs4:%=../include/@PACKAGE@/%) -libeixx_la_SOURCES = am.cpp atom.cpp defaults.cpp basic_otp_node_local.cpp \ +libeixx_la_SOURCES = am.cpp atom.cpp defaults.cpp ref.cpp \ + basic_otp_node_local.cpp \ $(eixx_headers:%=../include/@PACKAGE@/%) libeixx_la_LTADD = -version-info 0:1 -shared libeixx_la_LIBS = $(BOOST_THREAD_LIB) $(CRYPTO_LIBS) diff --git a/src/am.cpp b/src/am.cpp index 3e8a93d..eb7856e 100644 --- a/src/am.cpp +++ b/src/am.cpp @@ -1,3 +1,27 @@ +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the eixx (Erlang C++ Interface) Library. + +Copyright (C) 2010 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ + #include namespace EIXX_NAMESPACE { diff --git a/src/atom.cpp b/src/atom.cpp index 79147c1..9b5b114 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -1,3 +1,27 @@ +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the eixx (Erlang C++ Interface) Library. + +Copyright (C) 2010 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ + #include #include //#include @@ -10,5 +34,7 @@ namespace EIXX_NAMESPACE { return s_atom_table; } + const atom marshal::atom::null = atom(); + } // namespace EIXX_NAMESPACE diff --git a/src/basic_otp_node_local.cpp b/src/basic_otp_node_local.cpp index 38e0651..dfbc9d9 100644 --- a/src/basic_otp_node_local.cpp +++ b/src/basic_otp_node_local.cpp @@ -1,9 +1,9 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +This file is part of the eixx (Erlang C++ Interface) Library. -Copyright (C) 2005 Hector Rivas Gandara +Copyright (C) 2010 Serge Aleynikov This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/src/defaults.cpp b/src/defaults.cpp index 65676fa..3fce93a 100644 --- a/src/defaults.cpp +++ b/src/defaults.cpp @@ -51,6 +51,7 @@ namespace EIXX_NAMESPACE { switch (s[0]) { case 'i': if (strncmp(p,"nt",m) == 0) r = LONG; + if (strncmp(p,"nteger",m) == 0) r = LONG; break; case 'd': if (strncmp(p,"ouble",m) == 0) r = DOUBLE; @@ -61,6 +62,11 @@ namespace EIXX_NAMESPACE { case 'b': if (strncmp(p,"ool",m) == 0) r = BOOL; else if (strncmp(p,"inary",m) == 0) r = BINARY; + else if (strncmp(p,"oolean",m)== 0) r = BOOL; + else if (strncmp(p,"yte",m) == 0) r = LONG; + break; + case 'c': + if (strncmp(p,"har",m) == 0) r = LONG; break; case 'a': if (strncmp(p,"tom",m) == 0) r = ATOM; @@ -73,7 +79,8 @@ namespace EIXX_NAMESPACE { else if (strncmp(p,"ort",m) == 0) r = PORT; break; case 'r': - if (strncmp(p,"ef",m) == 0) r = REF; + if (strncmp(p,"ef",m) == 0) r = REF; + else if (strncmp(p,"eference",m) == 0) r = REF; break; case 'v': if (strncmp(p,"ar",m) == 0) r = VAR; diff --git a/src/ref.cpp b/src/ref.cpp new file mode 100644 index 0000000..8616e67 --- /dev/null +++ b/src/ref.cpp @@ -0,0 +1,33 @@ +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the eixx (Erlang C++ Interface) Library. + +Copyright (C) 2010 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ + +#include +#include + +namespace EIXX_NAMESPACE { + + const uint32_t marshal::detail::s_ref_ids[] = {0, 0, 0}; + +} // namespace EIXX_NAMESPACE + diff --git a/src/server.hpp b/src/server.hpp index 61ab3c2..19c3fed 100644 --- a/src/server.hpp +++ b/src/server.hpp @@ -28,7 +28,7 @@ template class channel_manager : private boost::noncopyable { public: - typedef boost::shared_ptr channel_ptr; + typedef std::shared_ptr channel_ptr; /// Add the specified channel to the manager and start it. void start(channel_ptr c, bool a_connected = false) { @@ -46,7 +46,7 @@ class channel_manager : private boost::noncopyable /// Stop all channels. void stop_all() { std::for_each(m_channels.begin(), m_channels.end(), - boost::bind(&Connection::stop, _1)); + std::bind(&Connection::stop, _1)); m_channels.clear(); } @@ -70,7 +70,7 @@ class server : private boost::noncopyable { public: typedef Handler handler_type; - typedef boost::shared_ptr > pointer; + typedef std::shared_ptr > pointer; /// Construct the server to listen on the specified TCP address and port, and /// serve up files from the given directory. @@ -129,7 +129,7 @@ class server : private boost::noncopyable virtual void stop() { // Post a call to the stop function so that server::stop() is safe to call // from any thread. - m_io_service.post(boost::bind(&server::handle_stop, this)); + m_io_service.post(std::bind(&server::handle_stop, this)); } // Event handlers @@ -222,7 +222,7 @@ class tcp_server : public server< Handler > m_acceptor.listen(); m_acceptor.async_accept( static_cast&>(*m_new_channel).socket(), - boost::bind(&tcp_server::handle_accept, + std::bind(&tcp_server::handle_accept, this, boost::asio::placeholders::error)); } @@ -241,7 +241,7 @@ class tcp_server : public server< Handler > m_new_channel->handler(), channel::TCP); m_acceptor.async_accept( static_cast&>(*m_new_channel).socket(), - boost::bind(&tcp_server::handle_accept, + std::bind(&tcp_server::handle_accept, this, boost::asio::placeholders::error)); } } @@ -303,7 +303,7 @@ class uds_server : public server< Handler > // Open the acceptor m_acceptor.async_accept( static_cast&>(*m_new_channel).socket(), - boost::bind(&uds_server::handle_accept, + std::bind(&uds_server::handle_accept, this, boost::asio::placeholders::error)); } @@ -322,7 +322,7 @@ class uds_server : public server< Handler > m_new_channel->handler(), channel::UDS); m_acceptor.async_accept( static_cast&>(*m_new_channel).socket(), - boost::bind(&uds_server::handle_accept, + std::bind(&uds_server::handle_accept, this, boost::asio::placeholders::error)); } } diff --git a/src/test_node.cpp b/src/test_node.cpp index e49f77b..a16b639 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -1,7 +1,7 @@ #include #include +#include #include -#include #define BOOST_REQUIRE @@ -28,18 +28,23 @@ void on_status(otp_node& a_node, const otp_connection* a_con, otp_mailbox *g_io_server, *g_main; static atom g_rem_node; +static const atom S = atom("S"); +static const atom N1 = atom("N1"); +static const atom N2 = atom("N2"); +static const atom N3 = atom("N3"); + void on_io_request(otp_mailbox& a_mbox, boost::system::error_code& ec) { if (ec == boost::asio::error::operation_aborted) { eixx::transport_msg* p; while ((p = a_mbox.receive()) != NULL) { - boost::scoped_ptr l_tmsg(p); + std::unique_ptr l_tmsg(p); static eterm s_put_chars = eterm::format("{io_request,_,_,{put_chars,S}}"); varbind l_binding; if (s_put_chars.match(l_tmsg->msg(), &l_binding)) std::cerr << "I/O request from server: " - << l_binding["S"]->to_string() << std::endl; + << l_binding[S]->to_string() << std::endl; else std::cerr << "I/O server got a message: " << l_tmsg->msg() << std::endl; } @@ -53,20 +58,20 @@ void on_main_msg(otp_mailbox& a_mbox, boost::system::error_code& ec) { if (ec == boost::asio::error::operation_aborted) { eixx::transport_msg* p; while ((p = a_mbox.receive()) != NULL) { - boost::scoped_ptr l_tmsg(p); + std::unique_ptr l_tmsg(p); const eterm& l_msg = l_tmsg->msg(); - static eterm s_now_pattern = eterm::format("{rex, {N1, N2, N3}}"); - static eterm s_stop = atom("stop"); + static const eterm s_now_pattern = eterm::format("{rex, {N1, N2, N3}}"); + static const eterm s_stop = atom("stop"); varbind l_binding; if (s_now_pattern.match(l_msg, &l_binding)) { struct timeval tv = - { l_binding["N1"]->to_long() * 1000000 + - l_binding["N1"]->to_long(), - l_binding["N1"]->to_long() }; + { l_binding[N1]->to_long() * 1000000 + + l_binding[N2]->to_long(), + l_binding[N3]->to_long() }; struct tm tm; localtime_r(&tv.tv_sec, &tm); printf("Server time: %02d:%02d:%02d.%06ld\n", diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index a27d0b8..511b47f 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -32,20 +32,20 @@ using namespace eixx; BOOST_AUTO_TEST_CASE( test_atomable ) { - { - marshal::detail::atom_table<> t(10); - BOOST_REQUIRE_EQUAL(0u, t.lookup("")); - BOOST_REQUIRE_EQUAL(1u, t.lookup("abc")); - BOOST_REQUIRE_EQUAL(2u, t.lookup("aaaaa")); - BOOST_REQUIRE_EQUAL(1u, t.lookup("abc")); - } + util::atom_table<> t(10); + BOOST_REQUIRE_EQUAL(0, t.lookup(std::string())); + BOOST_REQUIRE_EQUAL(0, t.lookup("")); + int n = t.lookup("abc"); + BOOST_REQUIRE(0 < n); + BOOST_REQUIRE(0 < t.lookup("aaaaa")); + BOOST_REQUIRE_EQUAL(n, t.lookup("abc")); } BOOST_AUTO_TEST_CASE( test_atom ) { { atom a(""); - BOOST_REQUIRE_EQUAL(0u, a.index()); + BOOST_REQUIRE_EQUAL(0, a.index()); BOOST_REQUIRE_EQUAL(atom(), a); } { @@ -107,6 +107,12 @@ BOOST_AUTO_TEST_CASE( test_binary ) { binary et("Abc", 3, alloc); } { binary et("Abc", 3); } { binary et("Abc", 3, alloc); } + { + binary et{1,2,109}; + BOOST_REQUIRE_EQUAL(3u, et.size()); + BOOST_REQUIRE_EQUAL("<<1,2,109>>", eterm(et).to_string()); + BOOST_REQUIRE_EQUAL("<<>>", eterm(binary({}, alloc)).to_string()); + } { const uint8_t buf[] = {ERL_BINARY_EXT,0,0,0,3,97,98,99}; @@ -592,28 +598,16 @@ BOOST_AUTO_TEST_CASE( test_varbind ) { allocator_t alloc; - { - string a("Atom", alloc); - eterm ea(a); + varbind binding1; + binding1.bind(atom("Name"), 20.0); + binding1.bind(atom("Long"), 123); + varbind binding2; + binding2.bind(atom("Name"), atom("test")); + binding2.bind(atom("Other"), "vasya"); - eterm list[] = { - ea, - eterm(123) - }; + binding1.merge(binding2); - { - varbind binding1; - binding1.bind(a, list[0]); - binding1.bind("Long", list[1]); - varbind binding2; - binding2.bind("Atom", eterm(atom("test"))); - binding2.bind(string("Other", alloc), list[0]); - - binding1.merge(binding2); - - BOOST_REQUIRE_EQUAL(3ul, binding1.count()); - } - } + BOOST_REQUIRE_EQUAL(3ul, binding1.count()); } eterm f() { diff --git a/test/test_eterm_encode.cpp b/test/test_eterm_encode.cpp index 57168d1..a660fef 100644 --- a/test/test_eterm_encode.cpp +++ b/test/test_eterm_encode.cpp @@ -260,7 +260,7 @@ BOOST_AUTO_TEST_CASE( test_encode_trace ) BOOST_AUTO_TEST_CASE( test_encode_rpc ) { - static const char s_expected[] = { + static const unsigned char s_expected[] = { 131,104,2,103,100,0,14,69,67,71,46,72,49,46,48,48,49,64,102,49,54,0,0,0,1, 0,0,0,0,0,104,5,100,0,4,99,97,108,108,100,0,7,101,99,103,95,97,112,105,100, 0,11,114,101,103,95,112,114,111,99,101,115,115,108,0,0,0,5,100,0,3,69,67,71, diff --git a/test/test_eterm_format.cpp b/test/test_eterm_format.cpp index 330ea07..f284784 100644 --- a/test/test_eterm_format.cpp +++ b/test/test_eterm_format.cpp @@ -102,8 +102,8 @@ BOOST_AUTO_TEST_CASE( test_eterm_format_const ) { allocator_t alloc; - eterm et = eterm::format(alloc, - "[~i, 10, 2.5, abc, \"efg\", {~f, ~i}, ~a]", + eterm et = eterm::format(alloc, + "[~i, 10, 2.5, abc, \"efg\", {~f, ~i}, ~a]", 1, 2.1, 10, "xx"); BOOST_REQUIRE_EQUAL(LIST, et.type()); @@ -124,4 +124,67 @@ BOOST_AUTO_TEST_CASE( test_eterm_format_compound ) BOOST_REQUIRE_EQUAL("[1,[{\"ab\",2},{xx,3}],{2.1,10},xyz,abc]", et.to_string()); } +BOOST_AUTO_TEST_CASE( test_eterm_var_type ) +{ + BOOST_REQUIRE_EQUAL(UNDEFINED, eterm::format("B").to_var().type()); + BOOST_REQUIRE_EQUAL(LONG, eterm::format("B::int()").to_var().type()); + BOOST_REQUIRE_EQUAL(LONG, eterm::format("B::byte()").to_var().type()); + BOOST_REQUIRE_EQUAL(LONG, eterm::format("B::char()").to_var().type()); + BOOST_REQUIRE_EQUAL(LONG, eterm::format("B::integer()").to_var().type()); + BOOST_REQUIRE_EQUAL(STRING, eterm::format("B::string()").to_var().type()); + BOOST_REQUIRE_EQUAL(ATOM, eterm::format("B::atom()").to_var().type()); + BOOST_REQUIRE_EQUAL(DOUBLE, eterm::format("B::float()").to_var().type()); + BOOST_REQUIRE_EQUAL(DOUBLE, eterm::format("B::double()").to_var().type()); + BOOST_REQUIRE_EQUAL(BINARY, eterm::format("B::binary()").to_var().type()); + BOOST_REQUIRE_EQUAL(BOOL, eterm::format("B::bool()").to_var().type()); + BOOST_REQUIRE_EQUAL(BOOL, eterm::format("B::boolean()").to_var().type()); + BOOST_REQUIRE_EQUAL(LIST, eterm::format("B::list()").to_var().type()); + BOOST_REQUIRE_EQUAL(TUPLE, eterm::format("B::tuple()").to_var().type()); + BOOST_REQUIRE_EQUAL(PID, eterm::format("B::pid()").to_var().type()); + BOOST_REQUIRE_EQUAL(REF, eterm::format("B::ref()").to_var().type()); + BOOST_REQUIRE_EQUAL(REF, eterm::format("B::reference()").to_var().type()); + BOOST_REQUIRE_EQUAL(PORT, eterm::format("B::port()").to_var().type()); +} +BOOST_AUTO_TEST_CASE( test_eterm_mfa_format ) +{ + atom m, f; + eterm args; + + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b()")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b().")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b()\t")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b()\t .")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b() ")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b()\n.")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b( %comment\n).")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b().%comment")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b(10)")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b(10).")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "aa:bb(10)")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b(10,20).")); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b(~i).", 10)); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b(~f,~i).", 20.0, 10)); + BOOST_REQUIRE_NO_THROW(eterm::format(m, f, args, "a:b([~i,1], {ok,'a'}).", 10)); +} + +BOOST_AUTO_TEST_CASE( test_eterm_mfa_format_bad ) +{ + atom m, f; + eterm args; + + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a:b(1, %comment\n"), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a:b(1, %comment 2)."), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "("), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, ")"), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "."), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "aa"), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a("), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a:b("), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a.b()"), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a:b(10 20)"), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a:b(10. 20)"), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a:b(10.(20)"), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a:b(~i,~i]", 10, 20), err_format_exception); + BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a:b([[~i,20],]", 10), err_format_exception); +} \ No newline at end of file diff --git a/test/test_eterm_match.cpp b/test/test_eterm_match.cpp index fdbdb25..224ce34 100644 --- a/test/test_eterm_match.cpp +++ b/test/test_eterm_match.cpp @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include -#include +#include #include "test_alloc.hpp" #include @@ -53,19 +53,25 @@ BOOST_AUTO_TEST_CASE( test_match1 ) list ll(2, alloc); ll.push_back(eterm(1)); - ll.push_back(eterm(var())); + ll.push_back(eterm(var(LONG))); ll.close(); - // Add pattern = {test, _, [1, _]} + // Add pattern = {test, _::int(), [1, _::int()]} tuple ptup(3, alloc); ptup.push_back(eterm(atom("test"))); - ptup.push_back(var()); + ptup.push_back(var(LONG)); ptup.push_back(ll); eterm pattern(ptup); // Perform pattern match on the tuple bool res = tup.match(pattern); BOOST_REQUIRE(res); + + varbind vb; + res = tup.match(pattern, &vb); + BOOST_REQUIRE(res); + + BOOST_REQUIRE_EQUAL(0u, vb.count()); } } @@ -129,21 +135,32 @@ BOOST_AUTO_TEST_CASE( test_match2 ) // Each pattern contains a variable N that will be bound with // the "pattern number" in each successful match. etm.push_back(eterm::format("{test, N, A}"), - boost::bind(&cb_t::operator(), &cb, _1, _2, _3), 1); + std::bind(&cb_t::operator(), &cb, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), 1); etm.push_back(eterm::format("{ok, N, B, _}"), - boost::bind(&cb_t::operator(), &cb, _1, _2, _3), 2); + std::bind(&cb_t::operator(), &cb, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), 2); etm.push_back(eterm::format("{error, N, Reason}"), - boost::bind(&cb_t::operator(), &cb, _1, _2, _3), 3); + std::bind(&cb_t::operator(), &cb, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), 3); // Remember the reference to last pattern. We'll try to delete it later. const eterm_pattern_action& action = etm.push_back(eterm::format("{xxx, [_, _, {c, N}], \"abc\", X}"), - boost::bind(&cb_t::operator(), &cb, _1, _2, _3), 4); + std::bind(&cb_t::operator(), &cb, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), 4); // Make sure we registered 4 pattern above. BOOST_REQUIRE_EQUAL(4u, etm.size()); + static const eterm t0 = atom("test"); + eterm f0 = eterm::format("test"); + bool m0 = t0.match(f0); + BOOST_REQUIRE(m0); // N = 1 + // Match the following terms against registered patters. - BOOST_REQUIRE(etm.match(eterm::format("{test, 1, 123}"))); // N = 1 + auto f1 = eterm::format("{test, 1, 123}"); + auto m1 = etm.match(f1); + BOOST_REQUIRE(m1); // N = 1 BOOST_REQUIRE(etm.match(eterm::format("{test, 1, 234}"))); // N = 1 BOOST_REQUIRE(etm.match(eterm::format("{ok, 2, 3, 4}"))); // N = 2 @@ -174,8 +191,16 @@ BOOST_AUTO_TEST_CASE( test_match2 ) BOOST_AUTO_TEST_CASE( test_match3 ) { { - const eterm e = eterm::format("{snap, x12, []}"); - const eterm p = eterm::format("{snap, N, L}"); + auto p = eterm::format("{ok, N, A}"); + auto e = eterm::format("{ok, 1, 2}"); + varbind b; + auto m = e.match(p, &b); + BOOST_REQUIRE(m); + } + + { + auto e = eterm::format("{snap, x12, []}"); + auto p = eterm::format("{snap, N, L}"); varbind binding; BOOST_REQUIRE(p.match(e, &binding)); const eterm* n = binding.find("N"); @@ -187,17 +212,47 @@ BOOST_AUTO_TEST_CASE( test_match3 ) BOOST_REQUIRE_EQUAL(atom("x12"), n->to_atom()); BOOST_REQUIRE_EQUAL(list(), l->to_list()); } + + { + auto e = eterm::format("{1, 8#16, $a, 'Xbc', [{x, 2.0}]}"); + auto p = eterm::format("{A::int(), B::int(), C::char(), Q::atom(), D::list()}"); + varbind b; + bool m = e.match(p, &b); + BOOST_REQUIRE(m); + auto va = b.find("A"); + auto vb = b.find("B"); + auto vc = b.find("C"); + auto vd = b.find("D"); + auto vq = b.find("Q"); + BOOST_REQUIRE(va); + BOOST_REQUIRE(vb); + BOOST_REQUIRE(vc); + BOOST_REQUIRE(vd); + BOOST_REQUIRE_EQUAL(LONG, va->type()); + BOOST_REQUIRE_EQUAL(1, va->to_long()); + BOOST_REQUIRE_EQUAL(LONG, vb->type()); + BOOST_REQUIRE_EQUAL(14, vb->to_long()); + BOOST_REQUIRE_EQUAL(LONG, vc->type()); + BOOST_REQUIRE_EQUAL('a', vc->to_long()); + BOOST_REQUIRE_EQUAL(ATOM, vq->type()); + BOOST_REQUIRE_EQUAL(atom("Xbc"), vq->to_atom()); + BOOST_REQUIRE_EQUAL(LIST, vd->type()); + BOOST_REQUIRE_EQUAL(1u, vd->to_list().length()); + m = eterm::format("[{x, 2.0}]").match(*vd); + BOOST_REQUIRE(m); + } + { - const eterm t = eterm::format("[1,a,$b,\"xyz\",{1,10.0},[]]"); - const eterm pat = eterm::format("[A,B,C,D,E,F]"); + auto t = eterm::format("[1,a,$b,\"xyz\",{1,10.0},[]]"); + auto pat = eterm::format("[A,B,C,D,E,F]"); varbind p; BOOST_REQUIRE(pat.match(t, &p)); - const eterm* a = p.find("A"); - const eterm* b = p.find("B"); - const eterm* c = p.find("C"); - const eterm* d = p.find("D"); - const eterm* e = p.find("E"); - const eterm* f = p.find("F"); + auto a = p.find("A"); + auto b = p.find("B"); + auto c = p.find("C"); + auto f = p.find("F"); + auto d = p.find("D"); + auto e = p.find("E"); BOOST_REQUIRE(a); BOOST_REQUIRE(b); BOOST_REQUIRE(c); @@ -213,6 +268,78 @@ BOOST_AUTO_TEST_CASE( test_match3 ) } } +BOOST_AUTO_TEST_CASE( test_initializer_list ) +{ + const atom am_abc("abc"); + + { + eterm t{1, 20.0, am_abc, "xxx"}; + BOOST_REQUIRE_EQUAL(TUPLE, t.type()); + BOOST_REQUIRE_EQUAL(4u, t.to_tuple().size()); + BOOST_REQUIRE_EQUAL(1, t.to_tuple()[0].to_long()); + BOOST_REQUIRE_EQUAL(20.0, t.to_tuple()[1].to_double()); + BOOST_REQUIRE_EQUAL(am_abc, t.to_tuple()[2].to_atom()); + BOOST_REQUIRE_EQUAL("xxx", t.to_tuple()[3].to_str()); + + t = {eterm(1), eterm(20.0), eterm(atom("abc")), eterm("xxx")}; + BOOST_REQUIRE_EQUAL(TUPLE, t.type()); + BOOST_REQUIRE_EQUAL(4u, t.to_tuple().size()); + BOOST_REQUIRE_EQUAL(1, t.to_tuple()[0].to_long()); + BOOST_REQUIRE_EQUAL(20.0, t.to_tuple()[1].to_double()); + BOOST_REQUIRE_EQUAL(am_abc, t.to_tuple()[2].to_atom()); + BOOST_REQUIRE_EQUAL("xxx", t.to_tuple()[3].to_str()); + + t = {1, 20.0, am_abc, "xxx", {12, am_abc}}; + BOOST_REQUIRE_EQUAL(TUPLE, t.type()); + BOOST_REQUIRE_EQUAL(5u, t.to_tuple().size()); + BOOST_REQUIRE_EQUAL(1, t.to_tuple()[0].to_long()); + BOOST_REQUIRE_EQUAL(20.0, t.to_tuple()[1].to_double()); + BOOST_REQUIRE_EQUAL(am_abc, t.to_tuple()[2].to_atom()); + BOOST_REQUIRE_EQUAL(2u, t.to_tuple()[4].to_tuple().size()); + BOOST_REQUIRE_EQUAL(12, t.to_tuple()[4].to_tuple()[0].to_long()); + BOOST_REQUIRE_EQUAL(am_abc, t.to_tuple()[4].to_tuple()[1].to_atom()); + } + + { + eterm t = list{1, 20.0, am_abc, "xxx"}; + BOOST_REQUIRE_EQUAL(LIST, t.type()); + BOOST_REQUIRE_EQUAL(4u, t.to_list().length()); + auto it = t.to_list().begin(); + BOOST_REQUIRE_EQUAL(1, it->to_long()); + BOOST_REQUIRE_EQUAL(20.0, (++it)->to_double()); + BOOST_REQUIRE_EQUAL(am_abc, (++it)->to_atom()); + BOOST_REQUIRE_EQUAL("xxx", (++it)->to_str()); + + t = list{eterm(1), eterm(20.0), eterm(atom("abc")), eterm("xxx")}; + it = t.to_list().begin(); + BOOST_REQUIRE_EQUAL(LIST, t.type()); + BOOST_REQUIRE_EQUAL(4u, t.to_list().length()); + BOOST_REQUIRE_EQUAL(1, it->to_long()); + BOOST_REQUIRE_EQUAL(20.0, (++it)->to_double()); + BOOST_REQUIRE_EQUAL(am_abc, (++it)->to_atom()); + BOOST_REQUIRE_EQUAL("xxx", (++it)->to_str()); + + t = list{1, 20.0, am_abc, "xxx", {12, am_abc}, list{3,4}}; + it = t.to_list().begin(); + BOOST_REQUIRE_EQUAL(LIST, t.type()); + BOOST_REQUIRE_EQUAL(6u, t.to_list().length()); + BOOST_REQUIRE_EQUAL(1, it->to_long()); + BOOST_REQUIRE_EQUAL(20.0, (++it)->to_double()); + BOOST_REQUIRE_EQUAL(am_abc, (++it)->to_atom()); + BOOST_REQUIRE_EQUAL("xxx", (++it)->to_str()); + BOOST_REQUIRE_EQUAL(TUPLE, (++it)->type()); + auto tt = it->to_tuple(); + BOOST_REQUIRE_EQUAL(2u, tt.size()); + BOOST_REQUIRE_EQUAL(12, tt[0].to_long()); + BOOST_REQUIRE_EQUAL(am_abc, tt[1].to_atom()); + BOOST_REQUIRE_EQUAL(LIST, (++it)->type()); + auto l = it->to_list().begin(); + BOOST_REQUIRE_EQUAL(2u, it->to_list().length()); + BOOST_REQUIRE_EQUAL(3, (l++)->to_long()); + BOOST_REQUIRE_EQUAL(4, (l++)->to_long()); + } +} + static void run(int n) { static const int iterations = ::getenv("ITERATIONS") ? atoi(::getenv("ITERATIONS")) : 1; @@ -231,7 +358,9 @@ static void run(int n) for(int i=0; i < iterations; i++) { BOOST_REQUIRE(!sp.match(eterm::format(alloc, "{ok, 1, 3, 4}"))); - BOOST_REQUIRE_EQUAL((n == 1), sp.match(eterm::format(alloc, "{ok, 1, 2}"))); // N = 1 + auto f1 = eterm::format(alloc, "{ok, 1, 2}"); + auto m1 = sp.match(f1); + BOOST_REQUIRE_EQUAL((n == 1), m1); // N = 1 BOOST_REQUIRE(sp.match(eterm::format(alloc, "{error, 2, not_found}"))); // N = 2 BOOST_REQUIRE(!sp.match(eterm::format(alloc, "{test, 3}"))); @@ -342,3 +471,26 @@ BOOST_AUTO_TEST_CASE( test_match_list_tail ) BOOST_REQUIRE_EQUAL(LIST, tail->type()); } +BOOST_AUTO_TEST_CASE( test_eterm_var_match ) +{ + BOOST_REQUIRE(eterm(1) .match(eterm::format("B"))); + BOOST_REQUIRE(eterm(10) .match(eterm::format("B::int()"))); + BOOST_REQUIRE(eterm('c') .match(eterm::format("B::int()"))); + BOOST_REQUIRE(eterm('c') .match(eterm::format("B::byte()"))); + BOOST_REQUIRE(eterm('c') .match(eterm::format("B::char()"))); + BOOST_REQUIRE(eterm("abc") .match(eterm::format("B"))); + BOOST_REQUIRE(eterm("abc") .match(eterm::format("B::string()"))); + BOOST_REQUIRE(eterm(atom("abc")) .match(eterm::format("B"))); + BOOST_REQUIRE(eterm(atom("abc")) .match(eterm::format("B::atom()"))); + BOOST_REQUIRE(eterm(10.123) .match(eterm::format("B::float()"))); + BOOST_REQUIRE(eterm(10.123) .match(eterm::format("B::double()"))); + BOOST_REQUIRE(eterm(binary{1,2,3}) .match(eterm::format("B::binary()"))); + BOOST_REQUIRE(eterm(true) .match(eterm::format("B::boolean()"))); + BOOST_REQUIRE(eterm(false) .match(eterm::format("B::bool()"))); + BOOST_REQUIRE(eterm(list{1,2.0,"a"}).match(eterm::format("B::list()"))); + BOOST_REQUIRE(eterm({1,2.0,"a"}) .match(eterm::format("B::tuple()"))); + BOOST_REQUIRE(eterm(epid()) .match(eterm::format("B::pid()"))); + BOOST_REQUIRE(eterm(port()) .match(eterm::format("B::port()"))); + BOOST_REQUIRE(eterm(ref()) .match(eterm::format("B::ref()"))); + BOOST_REQUIRE(eterm(ref()) .match(eterm::format("B::reference()"))); +} diff --git a/test/test_mailbox.cpp b/test/test_mailbox.cpp index 50801eb..fe1dba7 100644 --- a/test/test_mailbox.cpp +++ b/test/test_mailbox.cpp @@ -40,8 +40,8 @@ BOOST_AUTO_TEST_CASE( test_mailbox ) { boost::asio::io_service io; otp_node node(io, "a"); - atom am_io_server("io_server"); - atom am_main("main"); + const atom am_io_server("io_server"); + const atom am_main("main"); //std::cerr << "mailbox count " << node.registry().count() << std::endl; { @@ -49,8 +49,6 @@ BOOST_AUTO_TEST_CASE( test_mailbox ) otp_mailbox::pointer b(node.create_mailbox(am_main)); //BOOST_REQUIRE_NE(*a.get(), *b.get()); - - otp_mailbox* ag = node.get_mailbox(atom("io_server")); otp_mailbox* bg = node.get_mailbox(atom("main")); @@ -61,7 +59,7 @@ BOOST_AUTO_TEST_CASE( test_mailbox ) BOOST_REQUIRE_EQUAL(*a, *ag); BOOST_REQUIRE_EQUAL(*b, *bg); } - + //node.registry().erase(a.get()); //node.registry().erase(b.get()); } diff --git a/test/test_node.cpp b/test/test_node.cpp index 651677a..d84d511 100644 --- a/test/test_node.cpp +++ b/test/test_node.cpp @@ -30,6 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***** END LICENSE BLOCK ***** */ +#include #include #include "test_alloc.hpp" #include @@ -38,7 +39,7 @@ using namespace eixx; BOOST_AUTO_TEST_CASE( test_node ) { - std::string l_hostname("gbox-car-00"), l_resolved; + std::string l_hostname("localhost"), l_resolved; boost::asio::io_service svc; boost::asio::ip::tcp::resolver resolver(svc); boost::asio::ip::tcp::resolver::query query(l_hostname, ""); From fc470b62bbd98d10b42cb37d1c099bb7a0682a19 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 10 Oct 2013 15:49:38 -0400 Subject: [PATCH 007/185] Renamed methods in transport_msg --- include/eixx/connect/basic_otp_connection.hpp | 54 ++++++++------- include/eixx/connect/basic_otp_mailbox.hpp | 18 ++--- include/eixx/connect/basic_otp_node.hpp | 24 +++---- include/eixx/connect/basic_otp_node.ipp | 11 ++- include/eixx/connect/basic_otp_node_local.hpp | 14 ++-- include/eixx/connect/transport_msg.hpp | 36 +++++----- .../eixx/connect/transport_otp_connection.hpp | 44 ++++++------ .../eixx/connect/transport_otp_connection.ipp | 22 +++--- .../connect/transport_otp_connection_tcp.hpp | 13 ++-- .../connect/transport_otp_connection_tcp.ipp | 68 ++++++++++--------- .../connect/transport_otp_connection_uds.hpp | 15 ++-- include/eixx/marshal/am.hpp | 25 +++++-- src/am.cpp | 26 +++++-- src/basic_otp_node_local.cpp | 14 ++-- src/test_node.cpp | 8 +-- 15 files changed, 219 insertions(+), 173 deletions(-) diff --git a/include/eixx/connect/basic_otp_connection.hpp b/include/eixx/connect/basic_otp_connection.hpp index 4967a1b..6ce7053 100644 --- a/include/eixx/connect/basic_otp_connection.hpp +++ b/include/eixx/connect/basic_otp_connection.hpp @@ -59,7 +59,7 @@ class basic_otp_connection typename connection_type::pointer m_transport; basic_otp_node* m_node; atom m_remote_nodename; - std::string m_cookie; + atom m_cookie; const Alloc& m_alloc; connect_completion_handler m_on_connect_status; bool m_connected; @@ -68,14 +68,16 @@ class basic_otp_connection bool m_abort; basic_otp_connection( - connect_completion_handler h, - boost::asio::io_service& a_svc, - basic_otp_node* a_node, const atom& a_remote_node, - const std::string& a_cookie, int a_reconnect_secs = 0, - const Alloc& a_alloc = Alloc()) + connect_completion_handler h, + boost::asio::io_service& a_svc, + basic_otp_node* a_node, + atom a_remote_nodename, + atom a_cookie, + int a_reconnect_secs = 0, + const Alloc& a_alloc = Alloc()) : m_io_service(a_svc) , m_node(a_node) - , m_remote_nodename(a_remote_node) + , m_remote_nodename(a_remote_nodename) , m_cookie(a_cookie) , m_alloc(a_alloc) , m_connected(false) @@ -86,8 +88,8 @@ class basic_otp_connection BOOST_ASSERT(a_node != NULL); m_on_connect_status = h; m_transport = connection_type::create( - m_io_service, this, a_node->nodename().to_string(), - a_remote_node.to_string(), a_cookie, a_alloc); + m_io_service, this, a_node->nodename(), + a_remote_nodename, a_cookie, a_alloc); } void reconnect() { @@ -110,8 +112,8 @@ class basic_otp_connection } m_transport = connection_type::create( - m_io_service, this, m_node->nodename().to_string(), - m_remote_nodename.to_string(), m_cookie, m_alloc); + m_io_service, this, m_node->nodename(), + m_remote_nodename, m_cookie, m_alloc); } public: @@ -121,7 +123,7 @@ class basic_otp_connection connection_type* transport() { return m_transport.get(); } verbose_type verbose() const { return m_node->verbose(); } basic_otp_node* node() { return m_node; } - const atom& remote_node() const { return m_remote_nodename; } + atom remote_nodename() const { return m_remote_nodename; } bool connected() const { return m_connected; } int reconnect_timeout() const { return m_reconnect_secs; } @@ -130,15 +132,16 @@ class basic_otp_connection void reconnect_timeout(size_t a_reconnect_secs) { m_reconnect_secs = a_reconnect_secs; } static pointer - connect(connect_completion_handler h, - boost::asio::io_service& a_svc, - basic_otp_node* a_node, const atom& a_remote_node, - const std::string& a_cookie, - int a_reconnect_secs = 0, - const Alloc& a_alloc = Alloc()) + connect(connect_completion_handler h, + boost::asio::io_service& a_svc, + basic_otp_node* a_node, + atom a_remote_nodename, + atom a_cookie, + int a_reconnect_secs = 0, + const Alloc& a_alloc = Alloc()) { pointer p(new basic_otp_connection( - h, a_svc, a_node, a_remote_node, a_cookie, a_reconnect_secs, a_alloc)); + h, a_svc, a_node, a_remote_nodename, a_cookie, a_reconnect_secs, a_alloc)); return p; } @@ -156,7 +159,7 @@ class basic_otp_connection if (m_abort) return; else - throw err_connection("Not connected to node", remote_node()); + throw err_connection("Not connected to node", remote_nodename()); } else if (m_connected) m_transport->send(a_msg); // If not connected, the message sending will be ignored @@ -172,7 +175,7 @@ class basic_otp_connection m_on_connect_status(this, std::string()); if (unlikely(verbose() > VERBOSE_NONE)) { report_status(REPORT_INFO, - "Connected to node: " + a_con->remote_node()); + "Connected to node: " + a_con->remote_nodename().to_string()); } } @@ -186,7 +189,8 @@ class basic_otp_connection m_on_connect_status(this, a_error); else if (unlikely(verbose() > VERBOSE_NONE)) { std::stringstream s; - s << "Failed to connect to node " << a_con->remote_node() << ": " << a_error; + s << "Failed to connect to node " + << a_con->remote_nodename() << ": " << a_error; report_status(REPORT_ERROR, s.str()); } reconnect(); @@ -197,12 +201,12 @@ class basic_otp_connection if (unlikely(verbose() > VERBOSE_DEBUG)) { std::stringstream s; - s << "Disconnected from node: " << a_con->remote_node() + s << "Disconnected from node: " << a_con->remote_nodename() << " (" << err.message() << ')'; report_status(REPORT_ERROR, s.str()); } if (m_node) - m_node->on_disconnect_internal(*this, a_con->remote_node(), err); + m_node->on_disconnect_internal(*this, a_con->remote_nodename(), err); m_transport.reset(); reconnect(); @@ -210,7 +214,7 @@ class basic_otp_connection void on_error(connection_type* a_con, const std::string& s) { std::stringstream str; - str << "Error in communication with node: " << a_con->remote_node() + str << "Error in communication with node: " << a_con->remote_nodename() << "\n " << s; report_status(REPORT_ERROR, str.str()); } diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index a62cca2..b9ab07c 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -377,22 +377,22 @@ do_deliver(transport_msg* a_msg) try { switch (a_msg->type()) { case transport_msg::LINK: - BOOST_ASSERT(a_msg->to_pid() == self()); - m_links.insert(a_msg->from_pid()); + BOOST_ASSERT(a_msg->recipient_pid() == self()); + m_links.insert(a_msg->sender_pid()); delete a_msg; return; case transport_msg::UNLINK: - BOOST_ASSERT(a_msg->to_pid() == self()); - m_links.erase(a_msg->from_pid()); + BOOST_ASSERT(a_msg->recipient_pid() == self()); + m_links.erase(a_msg->sender_pid()); delete a_msg; return; case transport_msg::MONITOR_P: - BOOST_ASSERT((a_msg->to().type() == PID && a_msg->to_pid() == self()) - || a_msg->to().to_atom() == m_name); + BOOST_ASSERT((a_msg->recipient().type() == PID && a_msg->recipient_pid() == self()) + || a_msg->recipient().to_atom() == m_name); m_monitors.insert( - std::pair, epid >(a_msg->get_ref(), a_msg->from_pid())); + std::pair, epid >(a_msg->get_ref(), a_msg->sender_pid())); delete a_msg; return; @@ -408,8 +408,8 @@ do_deliver(transport_msg* a_msg) case transport_msg::EXIT2: case transport_msg::EXIT2_TT: - BOOST_ASSERT(a_msg->to_pid() == self()); - m_links.erase(a_msg->from_pid()); + BOOST_ASSERT(a_msg->recipient_pid() == self()); + m_links.erase(a_msg->sender_pid()); m_queue.push_back(a_msg); break; diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index 16a6cf8..0146e43 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -96,7 +96,7 @@ class basic_otp_node: public basic_otp_node_local { static const size_t s_max_node_connections = init_default_hash_size(); return s_max_node_connections; } - + atom_con_hash_fun(conn_hash_map* a_map) : map(*a_map) {} size_t operator()(const atom& data) const { @@ -121,10 +121,10 @@ class basic_otp_node: public basic_otp_node_local { friend class basic_otp_connection; void on_disconnect_internal(const connection_t& a_con, - const std::string& a_remote_node, const boost::system::error_code& err) + atom a_remote_nodename, const boost::system::error_code& err) { if (on_disconnect) - on_disconnect(*this, a_con, a_remote_node, err); + on_disconnect(*this, a_con, a_remote_nodename, err); } void report_status(report_level a_level, const connection_t* a_con, const std::string& s); @@ -160,8 +160,8 @@ class basic_otp_node: public basic_otp_node_local { * @throws eterm_exception if there is an error in transport creation */ basic_otp_node(boost::asio::io_service& a_io_svc, - const atom& a_nodename = atom(), - const std::string& a_cookie = "", + const std::string& a_nodename = std::string(), + const std::string& a_cookie = std::string(), const Alloc& a_alloc = Alloc(), int8_t a_creation = -1) throw (err_bad_argument, err_connection, eterm_exception); @@ -256,8 +256,8 @@ class basic_otp_node: public basic_otp_node_local { * and is not started. */ template - void connect(CompletionHandler h, const atom& a_remote_node, - const std::string& a_cookie = "", size_t a_reconnect_secs = 0) + void connect(CompletionHandler h, atom a_remote_node, + atom a_cookie = atom(), size_t a_reconnect_secs = 0) throw(err_connection); /** @@ -269,15 +269,15 @@ class basic_otp_node: public basic_otp_node_local { * and is not started. */ template - void connect(CompletionHandler h, const atom& a_remote_node, size_t a_reconnect_secs = 0) + void connect(CompletionHandler h, atom a_remote_nodename, size_t a_reconnect_secs = 0) throw(err_connection) { - connect(h, a_remote_node, "", a_reconnect_secs); + connect(h, a_remote_nodename, atom(), a_reconnect_secs); } /// Get connection identified by the \a a_node name. /// @throws err_connection if not connected to \a a_node._ - connection_t& connection(const atom& a_nodename) const { + connection_t& connection(atom a_nodename) const { typename conn_hash_map::const_iterator l_con = m_connections.find(a_nodename); if (l_con == m_connections.end()) throw err_connection("Not connected to node", a_nodename); @@ -288,8 +288,8 @@ class basic_otp_node: public basic_otp_node_local { * Callback invoked on disconnect from a peer node */ boost::function< - // OtpNode OtpConnection RemoteNodeName ErrorCode - void (self&, const connection_t&, const std::string&, const boost::system::error_code&) + // OtpNode OtpConnection RemoteNodeName ErrorCode + void (self&, const connection_t&, atom, const boost::system::error_code&) > on_disconnect; /** diff --git a/include/eixx/connect/basic_otp_node.ipp b/include/eixx/connect/basic_otp_node.ipp index faefdb7..a99c78c 100644 --- a/include/eixx/connect/basic_otp_node.ipp +++ b/include/eixx/connect/basic_otp_node.ipp @@ -41,10 +41,10 @@ namespace connect { template basic_otp_node::basic_otp_node( boost::asio::io_service& a_io_svc, - const atom& a_nodename, const std::string& a_cookie, + const std::string& a_nodename, const std::string& a_cookie, const Alloc& a_alloc, int8_t a_creation) throw (err_bad_argument, err_connection, eterm_exception) - : basic_otp_node_local(a_nodename.to_string(), a_cookie) + : basic_otp_node_local(a_nodename, a_cookie) , m_creation((a_creation < 0 ? time(NULL) : (int)a_creation) & 0x03) // Creation counter , m_pid_count(1) , m_port_count(1) @@ -102,14 +102,13 @@ ref basic_otp_node::create_ref() { template template void basic_otp_node::connect( - CompletionHandler h, const atom& a_remote_node, const std::string& a_cookie, - size_t a_reconnect_secs) + CompletionHandler h, atom a_remote_node, atom a_cookie, size_t a_reconnect_secs) throw(err_connection) { lock_guard guard(m_lock); typename conn_hash_map::iterator it = m_connections.find(a_remote_node); if (it == m_connections.end()) { - const std::string& l_cookie = a_cookie.empty() ? cookie() : a_cookie; + atom l_cookie = a_cookie.empty() ? cookie() : a_cookie; typename connection_t::pointer con( connection_t::connect(h, m_io_service, this, a_remote_node, l_cookie, a_reconnect_secs)); @@ -160,7 +159,7 @@ void basic_otp_node::deliver(const transport_msg& a_msg) throw (err_bad_argument, err_no_process, err_connection) { try { - const eterm& l_to = a_msg.to(); + const eterm& l_to = a_msg.recipient(); basic_otp_mailbox* l_mbox = get_mailbox(l_to); l_mbox->deliver(a_msg); } catch (std::exception& e) { diff --git a/include/eixx/connect/basic_otp_node_local.hpp b/include/eixx/connect/basic_otp_node_local.hpp index a11e15c..d072085 100644 --- a/include/eixx/connect/basic_otp_node_local.hpp +++ b/include/eixx/connect/basic_otp_node_local.hpp @@ -62,19 +62,19 @@ class basic_otp_node_local { throw (std::runtime_error, err_bad_argument); /// Get node name in the form node@host. - const atom& nodename() const { return m_nodename; } + atom nodename() const { return m_nodename; } /// Get node name in the form node@host.name.com. - const std::string& longname() const { return m_longname; } + const std::string& longname() const { return m_longname; } /// Get name of the node without hostname - const std::string& alivename() const { return m_alivename; } + const std::string& alivename() const { return m_alivename; } /// Get host name - const std::string& hostname() const { return m_hostname; } + const std::string& hostname() const { return m_hostname; } /// Get cookie - const std::string& cookie() const { return m_cookie; } + atom cookie() const { return m_cookie; } /// Set the cookie void cookie(const std::string& a_cookie) { m_cookie = a_cookie; } @@ -87,9 +87,9 @@ class basic_otp_node_local { std::string m_longname; std::string m_alivename; std::string m_hostname; - std::string m_cookie; + atom m_cookie; - static std::string s_default_cookie; // Default cookie + static atom s_default_cookie; // Default cookie static std::string s_localhost; // localhost name }; diff --git a/include/eixx/connect/transport_msg.hpp b/include/eixx/connect/transport_msg.hpp index e419b3c..fc9b0cc 100644 --- a/include/eixx/connect/transport_msg.hpp +++ b/include/eixx/connect/transport_msg.hpp @@ -110,9 +110,9 @@ class transport_msg { } /// Return the term representing the message sender. The sender is - /// usually a pid, except for MONITOR_P_EXIT message type for which + /// usually a pid, except for MONITOR_P_EXIT message type for which /// the sender can be either pid or atom name. - const eterm& from() const { + const eterm& sender() const { switch (m_type) { case REG_SEND: case LINK: @@ -134,14 +134,14 @@ class transport_msg { /// This function may only raise exception for MONITOR_P_EXIT /// message types if the message sender is given by name rather than by pid. - const epid& from_pid() const throw (err_wrong_type) { - return from().to_pid(); + const epid& sender_pid() const throw (err_wrong_type) { + return sender().to_pid(); } /// Return the term representing the message sender. The sender is /// usually a pid, except for MONITOR_P|DEMONITOR_P message type for which /// the sender can be either pid or atom name. - const eterm& to() const { + const eterm& recipient() const { switch (m_type) { case REG_SEND: return m_cntrl[3]; @@ -167,12 +167,12 @@ class transport_msg { /// This function may only raise exception for MONITOR_P|DEMONITOR_P /// message types if the message sender is given by name rather than by pid. - const epid& to_pid() const throw (err_wrong_type) { - return to().to_pid(); + const epid& recipient_pid() const throw (err_wrong_type) { + return recipient().to_pid(); } - const atom& to_name() const throw (err_wrong_type) { - return to().to_atom(); + const atom& recipient_name() const throw (err_wrong_type) { + return recipient().to_atom(); } const eterm& trace_token() const throw (err_wrong_type) { @@ -221,8 +221,8 @@ class transport_msg { /// Set the current message to represent a SEND message containing \a a_msg to /// be sent to \a a_to pid. - void set_send(const epid& a_to, const eterm& a_msg, - const Alloc& a_alloc = Alloc()) + void set_send(const epid& a_to, const eterm& a_msg, + const Alloc& a_alloc = Alloc()) { const trace* token = trace::tracer(marshal::TRACE_GET); if (unlikely(token)) { @@ -238,8 +238,8 @@ class transport_msg { /// Set the current message to represent a REG_SEND message containing /// \a a_msg to be sent from \a a_from pid to \a a_to registered mailbox. - void set_reg_send(const epid& a_from, const atom& a_to, const eterm& a_msg, - const Alloc& a_alloc = Alloc()) + void set_reg_send(const epid& a_from, const atom& a_to, + const eterm& a_msg, const Alloc& a_alloc = Alloc()) { const trace* token = trace::tracer(marshal::TRACE_GET); if (unlikely(token)) { @@ -255,9 +255,10 @@ class transport_msg { /// Set the current message to represent a LINK message. void set_link(const epid& a_from, const epid& a_to, - const Alloc& a_alloc = Alloc()) + const Alloc& a_alloc = Alloc()) { - const tuple& l_cntrl = tuple::make(ERL_LINK, a_from, a_to, a_alloc); + const tuple& l_cntrl = + tuple::make(ERL_LINK, a_from, a_to, a_alloc); set(LINK, l_cntrl, NULL); } @@ -265,7 +266,8 @@ class transport_msg { void set_unlink(const epid& a_from, const epid& a_to, const Alloc& a_alloc = Alloc()) { - const tuple& l_cntrl = tuple::make(ERL_UNLINK, a_from, a_to, a_alloc); + const tuple& l_cntrl = + tuple::make(ERL_UNLINK, a_from, a_to, a_alloc); set(UNLINK, l_cntrl, NULL); } @@ -313,7 +315,7 @@ class transport_msg { } /// Set the current message to represent a MONITOR_EXIT message. - void set_monitor_exit(const epid& a_from, const epid& a_to, + void set_monitor_exit(const epid& a_from, const epid& a_to, const ref& a_ref, const eterm& a_reason, const Alloc& a_alloc = Alloc()) { diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index 0d22730..64cbdcd 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -76,9 +76,9 @@ class connection /// The handler used to process the incoming request. Handler* m_handler; connection_type m_type; - std::string m_remote_node; - std::string m_this_node; - std::string m_cookie; + atom m_remote_nodename; + atom m_this_node; + atom m_cookie; Alloc m_allocator; @@ -220,18 +220,18 @@ class connection static connection_type parse_connection_type(std::string& s) throw(std::runtime_error); - /// Establish connection to \a a_remote_node. The call is non-blocking - + /// Establish connection to \a a_remote_nodename. The call is non-blocking - /// it will immediately returned, and Handler's on_connect() or /// on_error() callback will be invoked on successful/failed connection /// status. - virtual void connect(const std::string& a_this_node, - const std::string& a_remote_node, - const std::string& a_cookie) + virtual void connect(atom a_this_node, + atom a_remote_nodename, + atom a_cookie) throw(std::runtime_error) { - m_this_node = a_this_node; - m_remote_node = a_remote_node; - m_cookie = a_cookie; + m_this_node = a_this_node; + m_remote_nodename = a_remote_nodename; + m_cookie = a_cookie; } /// Set the socket to non-blocking mode and issue on_connect() callback. @@ -281,12 +281,12 @@ class connection /// \endverbatim /// @param a_cookie security cookie. static pointer create( - boost::asio::io_service& a_svc, - handler_type* a_h, - const std::string& a_this_node, - const std::string& a_node, - const std::string& a_cookie, - const Alloc& a_alloc = Alloc()); + boost::asio::io_service& a_svc, + handler_type* a_h, + atom a_this_node, + atom a_node, + atom a_cookie, + const Alloc& a_alloc = Alloc()); virtual ~connection() { if (handler()->verbose() >= VERBOSE_TRACE) @@ -324,12 +324,12 @@ class connection virtual int native_socket() = 0; /// Address of connected peer. - virtual std::string peer_address() const { return ""; } - const std::string& remote_node() const { return m_remote_node; } - const std::string& this_node() const { return m_this_node; } - const std::string& cookie() const { return m_cookie; } - Handler* handler() { return m_handler; } - boost::asio::io_service& io_service() { return m_io_service; } + virtual std::string peer_address() const { return ""; } + atom remote_nodename() const { return m_remote_nodename; } + atom local_nodename() const { return m_this_node; } + atom cookie() const { return m_cookie; } + Handler* handler() { return m_handler; } + boost::asio::io_service& io_service() { return m_io_service; } /// Send a message \a a_msg to the remote node. void send(const transport_msg& a_msg); diff --git a/include/eixx/connect/transport_otp_connection.ipp b/include/eixx/connect/transport_otp_connection.ipp index dfb384c..e9ce2fb 100644 --- a/include/eixx/connect/transport_otp_connection.ipp +++ b/include/eixx/connect/transport_otp_connection.ipp @@ -59,15 +59,14 @@ typename connection::pointer connection::create( boost::asio::io_service& a_svc, Handler* a_h, - const std::string& a_this_node, - const std::string& a_node, - const std::string& a_cookie, + atom a_this_node, + atom a_node, + atom a_cookie, const Alloc& a_alloc) { - if (a_this_node.find('@') == std::string::npos) - THROW_RUNTIME_ERROR("Invalid name of this node: " << a_this_node); + BOOST_ASSERT(a_this_node.to_string().find('@') != std::string::npos); - std::string addr(a_node); + std::string addr(a_node.to_string()); connection_type con_type = parse_connection_type(addr); @@ -91,7 +90,7 @@ connection::create( default: THROW_RUNTIME_ERROR("Not implemented! (proto=" << con_type << ')'); } - p->connect(a_this_node, addr, a_cookie); + p->connect(a_this_node, a_node, a_cookie); return p; } @@ -186,16 +185,13 @@ handle_write(const boost::system::error_code& err) // We use operation_aborted as a user-initiated connection reset, // therefore check to substitute the error since bytes_transferred == 0 // means a connection loss. - boost::system::error_code e = - err == boost::asio::error::operation_aborted + boost::system::error_code e = err == boost::asio::error::operation_aborted ? boost::asio::error::not_connected : err; stop(e); return; } - for (std::deque::iterator - it = m_out_msg_queue[writing_queue()].begin(), - end = m_out_msg_queue[writing_queue()].end(); - it != end; ++it) { + auto& q = m_out_msg_queue[writing_queue()]; + for (auto it = q.begin(), end = q.end(); it != end; ++it) { const char* p = boost::asio::buffer_cast(*it); // Don't forget to adjust for the header magic byte. BOOST_ASSERT(*(p - 1) == s_header_magic); diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 6327fad..560ae94 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -142,8 +142,7 @@ class tcp_connection uint32_t m_remote_challenge; uint32_t m_our_challenge; - void connect(const std::string& a_this_node, - const std::string& a_remote_node, const std::string& a_cookie) + void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie) throw(std::runtime_error); std::shared_ptr > shared_from_this() { @@ -159,10 +158,16 @@ class tcp_connection void start(); std::string remote_alivename() const { - return this->remote_node().substr(0, this->remote_node().find('@')); + auto s = this->remote_nodename().to_string(); + auto n = s.find('@'); + BOOST_ASSERT(n != std::string::npos); + return s.substr(0, s.find('@')); } std::string remote_hostname() const { - return this->remote_node().substr(this->remote_node().find('@')+1); + auto s = this->remote_nodename().to_string(); + auto n = s.find('@'); + BOOST_ASSERT(n != std::string::npos); + return s.substr(s.find('@')+1); } void handle_resolve( diff --git a/include/eixx/connect/transport_otp_connection_tcp.ipp b/include/eixx/connect/transport_otp_connection_tcp.ipp index dabe574..7f9b5f9 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.ipp +++ b/include/eixx/connect/transport_otp_connection_tcp.ipp @@ -54,18 +54,17 @@ void tcp_connection::start() template void tcp_connection::connect( - const std::string& a_this_node, const std::string& a_remote_node, const std::string& a_cookie) - throw(std::runtime_error) + atom a_this_node, atom a_remote_node, atom a_cookie) throw(std::runtime_error) { using boost::asio::ip::tcp; - base_t::connect(a_this_node, a_remote_node, a_cookie); + BOOST_ASSERT(a_this_node.to_string().find('@') != std::string::npos); - if (a_this_node.find('@', 0) == std::string::npos) - THROW_RUNTIME_ERROR("Invalid format of this_node: " << a_this_node); - if (a_remote_node.find('@', 0) == std::string::npos) + if (a_remote_node.to_string().find('@') == std::string::npos) THROW_RUNTIME_ERROR("Invalid format of remote_node: " << a_remote_node); + base_t::connect(a_this_node, a_remote_node, a_cookie); + //boost::system::error_code err = boost::asio::error::host_not_found; std::stringstream es; @@ -94,7 +93,7 @@ void tcp_connection::handle_resolve( BOOST_ASSERT(m_state == CS_WAIT_RESOLVE); if (err) { std::stringstream str; str << "Error resolving address of node '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); return; } @@ -141,7 +140,7 @@ void tcp_connection::handle_epmd_connect( std::placeholders::_1, ++ep_iterator)); } else { std::stringstream str; str << "Error connecting to epmd at host '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); } @@ -153,7 +152,7 @@ void tcp_connection::handle_epmd_write(const boost::system::erro BOOST_ASSERT(m_state == CS_WAIT_EPMD_WRITE_DONE); if (err) { std::stringstream str; str << "Error writing to epmd at host '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -175,7 +174,7 @@ void tcp_connection::handle_epmd_read_header( BOOST_ASSERT(m_state == CS_WAIT_EPMD_REPLY); if (err) { std::stringstream str; str << "Error reading response from epmd at host '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -186,7 +185,7 @@ void tcp_connection::handle_epmd_read_header( if (res != EI_EPMD_PORT2_RESP) { // response type std::stringstream str; str << "Error unknown response from epmd at host '" - << this->remote_node() << "': " << res; + << this->remote_nodename() << "': " << res; this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -202,7 +201,8 @@ void tcp_connection::handle_epmd_read_header( } if (n) { // Got negative response - std::stringstream str; str << "Node " << this->remote_node() << " not known to epmd!"; + std::stringstream str; + str << "Node " << this->remote_nodename() << " not known to epmd!"; this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -230,7 +230,7 @@ void tcp_connection::handle_epmd_read_body( BOOST_ASSERT(m_state == CS_WAIT_EPMD_REPLY); if (err) { std::stringstream str; str << "Error reading response body from epmd at host '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -264,7 +264,7 @@ void tcp_connection::handle_epmd_read_body( if (m_dist_version <= 4) { std::stringstream str; str << "Incompatible version " << m_dist_version - << " of remote node '" << this->remote_node() << "'"; + << " of remote node '" << this->remote_nodename() << "'"; this->handler()->on_connect_failure(this, str.str()); return; } @@ -282,7 +282,8 @@ void tcp_connection::handle_connect(const boost::system::error_c { BOOST_ASSERT(m_state == CS_WAIT_CONNECT); if (err) { - std::stringstream str; str << "Cannot connect to node " << this->remote_node() + std::stringstream str; + str << "Cannot connect to node " << this->remote_nodename() << " at port " << m_peer_endpoint.port() << ": " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); @@ -291,7 +292,7 @@ void tcp_connection::handle_connect(const boost::system::error_c if (this->handler()->verbose() >= VERBOSE_TRACE) { std::stringstream s; - s << "<- Connected to node: " << this->remote_node(); + s << "<- Connected to node: " << this->remote_nodename(); this->handler()->report_status(REPORT_INFO, s.str()); } @@ -301,7 +302,8 @@ void tcp_connection::handle_connect(const boost::system::error_c size_t siz = 2 + 1 + 2 + 4 + this->m_this_node.size(); if (siz > sizeof(m_buf_node)) { - std::stringstream str; str << "Node name too long: " << this->this_node() + std::stringstream str; + str << "Node name too long: " << this->local_nodename() << " [" << __FILE__ << ':' << __LINE__ << ']'; this->handler()->on_connect_failure(this, str.str()); m_socket.close(); @@ -318,7 +320,7 @@ void tcp_connection::handle_connect(const boost::system::error_c | DFLAG_NEW_FUN_TAGS | DFLAG_NEW_FLOATS | DFLAG_DIST_MONITOR)); - memcpy(w, this->this_node().c_str(), this->this_node().size()); + memcpy(w, this->local_nodename().c_str(), this->local_nodename().size()); if (this->handler()->verbose() >= VERBOSE_TRACE) { std::stringstream s; @@ -339,7 +341,7 @@ void tcp_connection::handle_write_name(const boost::system::erro BOOST_ASSERT(m_state == CS_WAIT_WRITE_CHALLENGE_DONE); if (err) { std::stringstream str; str << "Error writing auth challenge to node '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -359,7 +361,7 @@ void tcp_connection::handle_read_status_header( BOOST_ASSERT(m_state == CS_WAIT_STATUS); if (err) { std::stringstream str; str << "Error reading auth status from node '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -369,7 +371,7 @@ void tcp_connection::handle_read_status_header( size_t len = get16be(m_node_rd); if (len != 3) { - std::stringstream str; str << "Node " << this->remote_node() + std::stringstream str; str << "Node " << this->remote_nodename() << " rejected connection with reason: " << std::string(m_node_rd, len); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); @@ -398,7 +400,7 @@ void tcp_connection::handle_read_status_body( BOOST_ASSERT(m_state == CS_WAIT_STATUS); if (err) { std::stringstream str; str << "Error reading auth status body from node '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -410,7 +412,7 @@ void tcp_connection::handle_read_status_body( if (memcmp(m_node_rd, "sok", 3) != 0) { std::stringstream str; str << "Error invalid auth status response '" - << this->remote_node() << "': " << std::string(m_node_rd, 3); + << this->remote_nodename() << "': " << std::string(m_node_rd, 3); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -438,7 +440,7 @@ void tcp_connection::handle_read_challenge_header( BOOST_ASSERT(m_state == CS_WAIT_CHALLENGE); if (err) { std::stringstream str; str << "Error reading auth challenge from node '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -449,7 +451,7 @@ void tcp_connection::handle_read_challenge_header( if ((m_expect_size - 11) > (size_t)MAXNODELEN || m_expect_size > (size_t)((m_buf_node+1)-m_node_rd)) { std::stringstream str; str << "Error in auth status challenge node length " - << this->remote_node() << " : " << m_expect_size; + << this->remote_nodename() << " : " << m_expect_size; this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -475,7 +477,7 @@ void tcp_connection::handle_read_challenge_body( BOOST_ASSERT(m_state == CS_WAIT_CHALLENGE); if (err) { std::stringstream str; str << "Error reading auth challenge body from node '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -490,7 +492,7 @@ void tcp_connection::handle_read_challenge_body( char tag = get8(m_node_rd); if (tag != 'n') { std::stringstream str; str << "Error reading auth challenge tag '" - << this->remote_node() << "': " << tag; + << this->remote_nodename() << "': " << tag; this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -537,7 +539,7 @@ void tcp_connection::handle_write_challenge_reply(const boost::s BOOST_ASSERT(m_state == CS_WAIT_WRITE_CHALLENGE_REPLY_DONE); if (err) { std::stringstream str; str << "Error writing auth challenge reply to node '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -557,7 +559,7 @@ void tcp_connection::handle_read_challenge_ack_header( BOOST_ASSERT(m_state == CS_WAIT_CHALLENGE_ACK); if (err) { std::stringstream str; str << "Error reading auth challenge ack from node '" - << this->remote_node() << "': " + << this->remote_nodename() << "': " << (err == boost::asio::error::eof ? "Possibly bad cookie?" : err.message()); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); @@ -569,7 +571,7 @@ void tcp_connection::handle_read_challenge_ack_header( if (m_expect_size > sizeof(m_buf_node)-2) { std::stringstream str; str << "Error in auth status challenge ack length " - << this->remote_node() << " : " << m_expect_size; + << this->remote_nodename() << " : " << m_expect_size; this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -598,7 +600,7 @@ void tcp_connection::handle_read_challenge_ack_body( BOOST_ASSERT(m_state == CS_WAIT_CHALLENGE_ACK); if (err) { std::stringstream str; str << "Error reading auth challenge ack body from node '" - << this->remote_node() << "': " << err.message(); + << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -620,7 +622,7 @@ void tcp_connection::handle_read_challenge_ack_body( if (tag != 'a') { std::stringstream str; str << "Error reading auth challenge ack body tag '" - << this->remote_node() << "': " << tag; + << this->remote_nodename() << "': " << tag; this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; @@ -631,7 +633,7 @@ void tcp_connection::handle_read_challenge_ack_body( gen_digest(m_our_challenge, this->m_cookie.c_str(), (uint8_t*)expected_digest); if (memcmp(her_digest, expected_digest, 16) != 0) { std::stringstream str; str << "Authentication failure at node '" - << this->remote_node() << '!'; + << this->remote_nodename() << '!'; this->handler()->on_connect_failure(this, str.str()); m_socket.close(); return; diff --git a/include/eixx/connect/transport_otp_connection_uds.hpp b/include/eixx/connect/transport_otp_connection_uds.hpp index bd14048..55400dc 100644 --- a/include/eixx/connect/transport_otp_connection_uds.hpp +++ b/include/eixx/connect/transport_otp_connection_uds.hpp @@ -81,21 +81,22 @@ class uds_connection boost::asio::local::stream_protocol::socket m_socket; std::string m_uds_filename; - void connect(const std::string& a_this_node, - const std::string& a_remote_node, const std::string& a_cookie) + void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie) throw(std::runtime_error) { - base_t::connect(a_this_node, a_remote_node, a_cookie); + base_t::connect(a_this_node, a_remote_nodename, a_cookie); boost::system::error_code err; - boost::asio::local::stream_protocol::endpoint endpoint(a_remote_node); + boost::asio::local::stream_protocol::endpoint endpoint(a_remote_nodename.to_string()); m_socket.connect(endpoint, err); if (err) THROW_RUNTIME_ERROR("Error connecting to: " << m_uds_filename << ':' << err.message()); - size_t n = a_remote_node.find_last_of('/'); - this->m_remote_node = (n != std::string::npos) ? a_remote_node.substr(n+1) : a_remote_node; - m_uds_filename = a_remote_node; + auto s = a_remote_nodename.to_string(); + auto n = s.find_last_of('/'); + if (n != std::string::npos) s.erase(n); + this->m_remote_nodename = atom(s); + m_uds_filename = a_remote_nodename.to_string(); this->start(); } diff --git a/include/eixx/marshal/am.hpp b/include/eixx/marshal/am.hpp index 9a7c7a0..571ca2a 100644 --- a/include/eixx/marshal/am.hpp +++ b/include/eixx/marshal/am.hpp @@ -41,10 +41,27 @@ namespace EIXX_NAMESPACE { // Constant global atom values - extern const atom am_ANY_; - extern const atom am_true; - extern const atom am_false; - extern const atom am_undefined; + extern const atom am_ANY_; + extern const atom am_badrpc; + extern const atom am_call; + extern const atom am_cast; + extern const atom am_erlang; + extern const atom am_error; + extern const atom am_false; + extern const atom am_format; + extern const atom am_gen_cast; + extern const atom am_io_lib; + extern const atom am_latin1; + extern const atom am_noproc; + extern const atom am_noconnection; + extern const atom am_ok; + extern const atom am_request; + extern const atom am_rex; + extern const atom am_rpc; + extern const atom am_true; + extern const atom am_undefined; + extern const atom am_unsupported; + extern const atom am_user; } // namespace EIXX_NAMESPACE diff --git a/src/am.cpp b/src/am.cpp index eb7856e..c3b8ce4 100644 --- a/src/am.cpp +++ b/src/am.cpp @@ -23,13 +23,31 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include namespace EIXX_NAMESPACE { - const atom am_ANY_ = atom("_"); - const atom am_true = atom("true"); - const atom am_false = atom("false"); - const atom am_undefined = atom("undefined"); + const atom am_ANY_ = atom("_"); + const atom am_badrpc = atom("badrpc"); + const atom am_call = atom("call"); + const atom am_cast = atom("cast"); + const atom am_erlang = atom("erlang"); + const atom am_error = atom("error"); + const atom am_false = atom("false"); + const atom am_format = atom("format"); + const atom am_gen_cast = atom("$gen_cast"); + const atom am_io_lib = atom("io_lib"); + const atom am_latin1 = atom("latin1"); + const atom am_noproc = atom("noproc"); + const atom am_noconnection = atom("noconnection"); + const atom am_ok = atom("ok"); + const atom am_request = atom("request"); + const atom am_rex = atom("rex"); + const atom am_rpc = atom("rpc"); + const atom am_true = atom("true"); + const atom am_undefined = atom("undefined"); + const atom am_unsupported = atom("unsupported"); + const atom am_user = atom("user"); } // namespace EIXX_NAMESPACE diff --git a/src/basic_otp_node_local.cpp b/src/basic_otp_node_local.cpp index dfbc9d9..0ac86ad 100644 --- a/src/basic_otp_node_local.cpp +++ b/src/basic_otp_node_local.cpp @@ -33,7 +33,7 @@ namespace EIXX_NAMESPACE { namespace connect { namespace { - std::string get_default_cookie() { + atom get_default_cookie() { const char* home = getenv("HOME") ? getenv("HOME") : ""; if (home) { std::stringstream s; @@ -50,15 +50,17 @@ namespace { file >> cookie; size_t n = cookie.find('\n'); if (n != std::string::npos) cookie.erase(n); - return cookie; + if (cookie.size() > EI_MAX_COOKIE_SIZE) + throw err_bad_argument("Cookie size too long", cookie.size()); + return atom(cookie); } } - return "no_cookie"; + return atom(); } } // namespace -std::string basic_otp_node_local::s_default_cookie = get_default_cookie(); +atom basic_otp_node_local::s_default_cookie = get_default_cookie(); std::string basic_otp_node_local::s_localhost = boost::asio::ip::host_name(); basic_otp_node_local::basic_otp_node_local( @@ -72,11 +74,11 @@ void basic_otp_node_local::set_nodename( const std::string& a_nodename, const std::string& a_cookie) throw (std::runtime_error, err_bad_argument) { - m_cookie = a_cookie.empty() ? s_default_cookie : a_cookie; - if (m_cookie.size() > EI_MAX_COOKIE_SIZE) throw err_bad_argument("Cookie size too long", m_cookie.size()); + m_cookie = a_cookie.empty() ? s_default_cookie : atom(a_cookie); + std::string::size_type pos = a_nodename.find('@'); if (pos == std::string::npos) { diff --git a/src/test_node.cpp b/src/test_node.cpp index a16b639..cff1b07 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -106,16 +106,16 @@ void on_connect(otp_connection* a_con, const std::string& a_error) { // Make sure that remote node has a process registered as "test". // Try sending a message to it. - g_main->send_rpc(a_con->remote_node(), "erlang", "now", list::make()); + g_main->send_rpc(a_con->remote_nodename(), "erlang", "now", list::make()); // Send an rpc request to print a string. The remote - g_io_server->send_rpc_cast(a_con->remote_node(), atom("io"), atom("put_chars"), + g_io_server->send_rpc_cast(a_con->remote_nodename(), atom("io"), atom("put_chars"), list::make("This is a test string"), &g_io_server->self()); } void on_disconnect( otp_node& a_node, const otp_connection& a_con, - const std::string& a_remote_node, const boost::system::error_code& err) + atom a_remote_node, const boost::system::error_code& err) { std::cout << "Disconnected from remote node " << a_remote_node << std::endl; if (a_con.reconnect_timeout() == 0) @@ -158,7 +158,7 @@ int main(int argc, char* argv[]) { g_main = l_node.create_mailbox("main"); g_rem_node = atom(l_remote); - l_node.connect(&on_connect, l_remote, reconnect_secs); + l_node.connect(&on_connect, g_rem_node, reconnect_secs); //otp_connection::connection_type* l_transport = a_con->transport(); g_io_server->async_receive(&on_io_request); From 478b0038f695886cf9260a0bd4285fe4959a750d Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Fri, 11 Oct 2013 00:32:44 -0400 Subject: [PATCH 008/185] Added async_queue --- include/eixx/connect/basic_otp_mailbox.hpp | 5 +- include/eixx/marshal/am.hpp | 3 +- include/eixx/marshal/defaults.hpp | 10 +- include/eixx/util/async_queue.hpp | 184 +++++++++++++++++++++ include/eixx/util/async_wait_timeout.hpp | 51 +----- include/eixx/util/common.hpp | 3 + include/eixx/util/compiler_hints.hpp | 25 +++ include/eixx/util/timeout.hpp | 50 ++++++ src/am.cpp | 3 +- 9 files changed, 272 insertions(+), 62 deletions(-) create mode 100644 include/eixx/util/async_queue.hpp create mode 100644 include/eixx/util/compiler_hints.hpp create mode 100644 include/eixx/util/timeout.hpp diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index b9ab07c..9b601a5 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -40,6 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include #include #include @@ -104,6 +105,8 @@ class basic_otp_mailbox std::map, epid > m_monitors; queue_type m_queue; boost::asio::deadline_timer_ex m_deadline_timer; + std::chrono::time_point< + std::chrono::system_clock> m_free_time; // Cache time of this mbox boost::function< void (receive_handler_type f, boost::system::error_code&)> m_deadline_handler; @@ -128,7 +131,7 @@ class basic_otp_mailbox /// @param a_reg_remove when true the mailbox's pid is removed from registry. /// Only pass false when invoking from the registry on destruction. - void close(const eterm& a_reason = atom("normal"), bool a_reg_remove = true) { + void close(const eterm& a_reason = am_normal, bool a_reg_remove = true) { m_deadline_timer.cancel(); if (a_reg_remove) m_node.close_mailbox(this); diff --git a/include/eixx/marshal/am.hpp b/include/eixx/marshal/am.hpp index 571ca2a..79d4abc 100644 --- a/include/eixx/marshal/am.hpp +++ b/include/eixx/marshal/am.hpp @@ -52,8 +52,9 @@ namespace EIXX_NAMESPACE { extern const atom am_gen_cast; extern const atom am_io_lib; extern const atom am_latin1; - extern const atom am_noproc; extern const atom am_noconnection; + extern const atom am_noproc; + extern const atom am_normal; extern const atom am_ok; extern const atom am_request; extern const atom am_rex; diff --git a/include/eixx/marshal/defaults.hpp b/include/eixx/marshal/defaults.hpp index 9db1baf..bbf9f11 100644 --- a/include/eixx/marshal/defaults.hpp +++ b/include/eixx/marshal/defaults.hpp @@ -36,16 +36,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define EIXX_NAMESPACE eixx #endif -// Branch prediction optimization (see http://lwn.net/Articles/255364/) -#ifndef NO_HINT_BRANCH_PREDICTION -# define unlikely(expr) __builtin_expect(!!(expr), 0) -# define likely(expr) __builtin_expect(!!(expr), 1) -#else -# define unlikely(expr) (expr) -# define likely(expr) (expr) -#endif - #include +#include namespace EIXX_NAMESPACE { namespace marshal { diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp new file mode 100644 index 0000000..f189cdf --- /dev/null +++ b/include/eixx/util/async_queue.hpp @@ -0,0 +1,184 @@ +//---------------------------------------------------------------------------- +/// \file async_queue.hpp +/// \author Serge Aleynikov +//---------------------------------------------------------------------------- +/// \brief Multi-producer / single-consumer waitable queue. +//---------------------------------------------------------------------------- +// Created: 2013-10-10 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the eixx open-source project. + +Copyright (C) 2013 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ +#ifndef _EIXX_ASYNC_QUEUE_HPP +#define _EIXX_ASYNC_QUEUE_HPP + +#include +#include +#include +#include + +#include +#include + +namespace EIXX_NAMESPACE { +namespace util { + +using namespace boost::system::errc; + +class queue_canceled : public std::exception {}; + +template > +class blocking_queue +{ +public: + typedef boost::lockfree::queue< + T, boost::lockfree::allocator + > queue_type; + + typedef std::function async_handler; +private: + boost::asio::io_service& m_io; + queue_type m_queue; + int m_batch_size; + async_handler m_wait_handler; + boost::asio::waitable_timer m_timer; + bool m_is_canceled; + + static const system::error_code s_success; + static const system::error_code s_operation_canceled = + make_error_code(operation_canceled); + + // Dequeue up to m_batch_size of items and for each one call + // m_wait_handler + void process_queue(const system::error_code& ec) { + auto h = m_wait_handler; + if (h == nullptr) return; + + // Process up to m_batch_size items waiting on the queue. + // For each dequeued item call m_wait_handler + + bool remove = false; // Indicates if the callee wants to remove the handler + int i = 0; // Number of handler invocations + + bool canceled = m_is_canceled || ec == s_operation_canceled; + + for (; i < m_batch_size && !remove && !canceled; i++) { + T value; + if (m_queue.pop(value)) + remove = h(value, s_success); + else if (!i && ec == boost::asio::error:timeout) + remove = h(value, ec); + + if (remove) break; + } + + if (!remove) + if (!i && canceled) { + T dummy; + if (!h(dummy, s_operation_canceled)) // If returns false - don't remove the handler + return; + } else if (i == m_batch_size && !canceled && !m_queue.empty()) { + m_io.post(*this); + return; + } + } + + m_wait_handler = nullptr; + } + + // Called by io_service on timeout of m_timer + void operator() (const system::error_code& ec) { + process_queue(ec); + } + + // Called by io_service in response to enqueue(T&) + void operator() () { + process_queue(system::error_code()); + } + +public: + concurrent_queue(boost::asio::io_service& a_io, + int a_batch_size = 1, const Alloc& a_alloc = Alloc()) + : m_io(a_io) + , m_queue(255, a_alloc) + , m_batch_size(a_batch_size) + , m_timer(a_io) + , m_is_canceled(false) + {} + + void reset() { + m_is_canceled = true; + T value; + while (m_queue.pop(value)); + + if (m_wait_handler != nullptr) + m_io.post([this]() { (*this)(s_operation_canceled); }); + + m_is_canceled = false; + } + + bool canceled() const { return m_is_canceled; } + + bool enqueue(T const& data) { + if (m_is_canceled) return false; + + if (!m_queue.push(data)) + return false; + + if (m_wait_handler != nullptr) + m_io.post(*this); + } + + bool dequeue(T& value, const async_handler& a_on_data, + std::chrono::milliseconds a_wait_duration = -1) + { + if (m_queue.pop(value)) + return true; + else if (a_wait_duration.count() == 0) + return false; + + if (m_waiter_handler != nullptr) + throw std::runtime_error("Another waiting operation in progress!"); + m_wait_handler = a_on_data; + + if (m_queue.pop(value)) { + m_wait_handler = nullptr; + return true; + } + + if (a_wait_duration.count() < 0 || m_is_canceled) + return false; + + m_timer.expires_from_now(a_wait_duration); + m_timer.async_wait([this]() { + (*this)(boost::asio::error::make_error_code(boost::asio::error::timeout)); + }); + + return false; + } +}; + +} // namespace util +} // namespace EIXX_NAMESPACE + +#endif // _EIXX_ASYNC_QUEUE_HPP diff --git a/include/eixx/util/async_wait_timeout.hpp b/include/eixx/util/async_wait_timeout.hpp index 4ed529b..f1e0429 100644 --- a/include/eixx/util/async_wait_timeout.hpp +++ b/include/eixx/util/async_wait_timeout.hpp @@ -1,56 +1,7 @@ #ifndef _ASYNC_WAIT_TIMEOUT_HPP_ #define _ASYNC_WAIT_TIMEOUT_HPP_ -#include - -namespace boost { - -namespace asio { -namespace error { - - enum timer_errors { - timeout = ETIMEDOUT - }; - - namespace detail { - - struct timer_category : public boost::system::error_category { - const char* name() const noexcept { return "asio.timer"; } - - std::string message(int value) const { - return value == error::timeout - ? "Operation timed out" - : "asio.timer error"; - } - }; - - } // namespace detail - - inline const boost::system::error_category& get_timer_category() { - static detail::timer_category instance; - return instance; - } - -// static const boost::system::error_category& timer_category -// = boost::asio::error::get_timer_category(); - - inline boost::system::error_code make_error_code(boost::asio::error::timer_errors e) { - return boost::system::error_code( - static_cast(e), boost::asio::error::get_timer_category()); - } - -} // namespace error -} // namespace asio - -namespace system { - - template<> struct is_error_code_enum { - static const bool value = true; - }; - -} // namespace system - -#include +#include namespace asio { diff --git a/include/eixx/util/common.hpp b/include/eixx/util/common.hpp index c9d8981..9a94fc1 100644 --- a/include/eixx/util/common.hpp +++ b/include/eixx/util/common.hpp @@ -18,6 +18,9 @@ #include #include #include +#include +#include + #ifdef HAVE_CONFIG_H # include #endif diff --git a/include/eixx/util/compiler_hints.hpp b/include/eixx/util/compiler_hints.hpp new file mode 100644 index 0000000..df4b883 --- /dev/null +++ b/include/eixx/util/compiler_hints.hpp @@ -0,0 +1,25 @@ +//---------------------------------------------------------------------------- +/// \file compiler_hints.hpp +//---------------------------------------------------------------------------- +/// \namespace eixx +/// +/// This file contains various compiler optimization hints. +//---------------------------------------------------------------------------- +// Copyright (c) 2010 Serge Aleynikov +// Created: 2010-09-20 +//---------------------------------------------------------------------------- + +#ifndef _EIXX_COMPILER_HINTS_HPP_ +#define _EIXX_COMPILER_HINTS_HPP_ + +// Branch prediction optimization (see http://lwn.net/Articles/255364/) +#ifndef NO_HINT_BRANCH_PREDICTION +# define unlikely(expr) __builtin_expect(!!(expr), 0) +# define likely(expr) __builtin_expect(!!(expr), 1) +#else +# define unlikely(expr) (expr) +# define likely(expr) (expr) +#endif + +#endif // _EIXX_COMPILER_HINTS_HPP_ + diff --git a/include/eixx/util/timeout.hpp b/include/eixx/util/timeout.hpp new file mode 100644 index 0000000..15d3e93 --- /dev/null +++ b/include/eixx/util/timeout.hpp @@ -0,0 +1,50 @@ +#ifndef _EIXX_TIMEOUT_HPP_ +#define _EIXX_TIMEOUT_HPP_ + +#include + +namespace boost { + +namespace asio { +namespace error { + + enum timer_errors { + timeout = ETIMEDOUT + }; + + namespace detail { + + struct timer_category : public boost::system::error_category { + const char* name() const noexcept { return "asio.timer"; } + + std::string message(int value) const { + return value == error::timeout + ? "Operation timed out" + : "asio.timer error"; + } + }; + + } // namespace detail + + inline const boost::system::error_category& get_timer_category() { + static detail::timer_category instance; + return instance; + } + + inline boost::system::error_code make_error_code(boost::asio::error::timer_errors e) { + return boost::system::error_code( + static_cast(e), boost::asio::error::get_timer_category()); + } + +} // namespace error +} // namespace asio + +namespace system { + + template<> struct is_error_code_enum { + static const bool value = true; + }; + +} // namespace system + +#endif // _EIXX_TIMEOUT_HPP_ diff --git a/src/am.cpp b/src/am.cpp index c3b8ce4..9aaa3d6 100644 --- a/src/am.cpp +++ b/src/am.cpp @@ -38,8 +38,9 @@ namespace EIXX_NAMESPACE { const atom am_gen_cast = atom("$gen_cast"); const atom am_io_lib = atom("io_lib"); const atom am_latin1 = atom("latin1"); - const atom am_noproc = atom("noproc"); const atom am_noconnection = atom("noconnection"); + const atom am_noproc = atom("noproc"); + const atom am_normal = atom("normal"); const atom am_ok = atom("ok"); const atom am_request = atom("request"); const atom am_rex = atom("rex"); From 6c28417762fdb339d41ebe735c71744698933246 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sat, 12 Oct 2013 17:40:45 -0400 Subject: [PATCH 009/185] Work in progress --- include/eixx/alloc_pool.hpp | 2 +- include/eixx/alloc_pool_st.hpp | 2 +- include/eixx/alloc_std.hpp | 2 +- include/eixx/alloc_std_debug.hpp | 2 +- .../connect/basic_otp_mailbox_registry.hpp | 23 ++- include/eixx/eterm.hpp | 1 + include/eixx/marshal/defaults.hpp | 5 +- include/eixx/util/async_queue.hpp | 163 ++++++++++-------- include/eixx/util/async_wait_timeout.hpp | 5 +- include/eixx/util/timeout.hpp | 2 +- test/Makefile.am | 40 +++-- 11 files changed, 139 insertions(+), 108 deletions(-) diff --git a/include/eixx/alloc_pool.hpp b/include/eixx/alloc_pool.hpp index a2867e7..df59b75 100644 --- a/include/eixx/alloc_pool.hpp +++ b/include/eixx/alloc_pool.hpp @@ -32,8 +32,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_ALLOC_POOL_HPP_ #define _EIXX_ALLOC_POOL_HPP_ +#include // definition of EIXX_NAMESPACE #include -#include // definition of EIXX_NAMESPACE #define EIXX_USE_ALLOCATOR diff --git a/include/eixx/alloc_pool_st.hpp b/include/eixx/alloc_pool_st.hpp index e2f3225..6455eba 100644 --- a/include/eixx/alloc_pool_st.hpp +++ b/include/eixx/alloc_pool_st.hpp @@ -33,9 +33,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_ALLOC_POOL_HPP_ #define _EIXX_ALLOC_POOL_HPP_ +#include // definition of EIXX_NAMESPACE #include #include -#include // definition of EIXX_NAMESPACE #define EIXX_USE_ALLOCATOR diff --git a/include/eixx/alloc_std.hpp b/include/eixx/alloc_std.hpp index 8f349c2..2ffe613 100644 --- a/include/eixx/alloc_std.hpp +++ b/include/eixx/alloc_std.hpp @@ -33,7 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define _EIXX_ALLOC_STD_HPP_ #include -#include // definition of EIXX_NAMESPACE +#include // definition of EIXX_NAMESPACE #define EIXX_USE_ALLOCATOR diff --git a/include/eixx/alloc_std_debug.hpp b/include/eixx/alloc_std_debug.hpp index e59078c..4a5de35 100644 --- a/include/eixx/alloc_std_debug.hpp +++ b/include/eixx/alloc_std_debug.hpp @@ -33,9 +33,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_ALLOC_STD_HPP_ #define _EIXX_ALLOC_STD_HPP_ +#include // definition of EIXX_NAMESPACE #include #include -#include // definition of EIXX_NAMESPACE #define EIXX_USE_ALLOCATOR diff --git a/include/eixx/connect/basic_otp_mailbox_registry.hpp b/include/eixx/connect/basic_otp_mailbox_registry.hpp index 855125c..a35f130 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.hpp +++ b/include/eixx/connect/basic_otp_mailbox_registry.hpp @@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include namespace EIXX_NAMESPACE { namespace connect { @@ -45,18 +46,24 @@ using detail::lock_guard; template class basic_otp_mailbox_registry { - basic_otp_node& m_owner_node; - mutable Mutex m_lock; - - typedef basic_otp_mailbox mailbox_type; - typedef mailbox_type* mailbox_ptr; + typedef basic_otp_mailbox mailbox_type; + typedef mailbox_type* mailbox_ptr; + basic_otp_node& m_owner_node; // These are made mutable so that intrinsic cleanup is possible // of orphant entries. - mutable std::map m_by_name; - mutable std::map, mailbox_ptr> m_by_pid; + mutable Mutex m_lock; + mutable std::map m_by_name; + mutable std::map, mailbox_ptr> m_by_pid; + + // Cache of freed mailboxes + static std::queue s_free_list; public: - basic_otp_mailbox_registry(basic_otp_node& a_owner) : m_owner_node(a_owner) {} + basic_otp_mailbox_registry(basic_otp_node& a_owner) + : m_owner_node(a_owner) + { + + } ~basic_otp_mailbox_registry() { clear(); diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index 65a5076..186d8ad 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_ETERM_HPP_ #define _EIXX_ETERM_HPP_ +#include // definition of EIXX_NAMESPACE #include #include diff --git a/include/eixx/marshal/defaults.hpp b/include/eixx/marshal/defaults.hpp index bbf9f11..1fc578a 100644 --- a/include/eixx/marshal/defaults.hpp +++ b/include/eixx/marshal/defaults.hpp @@ -32,11 +32,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_DEFAULTS_HPP #define _EIXX_DEFAULTS_HPP -#ifndef EIXX_NAMESPACE -#define EIXX_NAMESPACE eixx -#endif - #include +#include #include namespace EIXX_NAMESPACE { diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index f189cdf..be34400 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -34,10 +34,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include +#include #include -#include +#include +#include +#include -#include +#include // definition of EIXX_NAMESPACE #include namespace EIXX_NAMESPACE { @@ -45,137 +48,151 @@ namespace util { using namespace boost::system::errc; -class queue_canceled : public std::exception {}; - -template > -class blocking_queue +/** + * Implements an asyncronous multiple-writer-single-reader queue + * for use with BOOST ASIO. + */ +template> +struct async_queue : std::enable_shared_from_this> { -public: typedef boost::lockfree::queue< - T, boost::lockfree::allocator + T, boost::lockfree::allocator, + boost::lockfree::capacity<255> > queue_type; - typedef std::function async_handler; + typedef std::function< + bool (T&, const boost::system::error_code& ec) + > async_handler; private: boost::asio::io_service& m_io; queue_type m_queue; int m_batch_size; - async_handler m_wait_handler; - boost::asio::waitable_timer m_timer; + boost::asio::system_timer m_timer; bool m_is_canceled; - static const system::error_code s_success; - static const system::error_code s_operation_canceled = - make_error_code(operation_canceled); - // Dequeue up to m_batch_size of items and for each one call // m_wait_handler - void process_queue(const system::error_code& ec) { - auto h = m_wait_handler; + void process_queue(async_handler h, std::chrono::milliseconds repeat) { if (h == nullptr) return; // Process up to m_batch_size items waiting on the queue. // For each dequeued item call m_wait_handler - bool remove = false; // Indicates if the callee wants to remove the handler - int i = 0; // Number of handler invocations - - bool canceled = m_is_canceled || ec == s_operation_canceled; + int i = 0; // Number of handler invocations - for (; i < m_batch_size && !remove && !canceled; i++) { - T value; - if (m_queue.pop(value)) - remove = h(value, s_success); - else if (!i && ec == boost::asio::error:timeout) - remove = h(value, ec); + bool canceled = m_is_canceled; - if (remove) break; - } + if (!canceled) + for (; i < m_batch_size; i++) { + T value; + if (m_queue.pop(value)) + if (!h(value, boost::system::error_code())) // If handler returns false - break + break; + } - if (!remove) - if (!i && canceled) { - T dummy; - if (!h(dummy, s_operation_canceled)) // If returns false - don't remove the handler - return; - } else if (i == m_batch_size && !canceled && !m_queue.empty()) { - m_io.post(*this); - return; + // If we haven't processed any data and the operation was canceled + // invoke the callback to see if we need to remove the handler + if (!i && canceled) { + T dummy; + h(dummy, boost::asio::error::eof); + } else if (!canceled) { + if (i == m_batch_size && !m_queue.empty()) { + // There's more data to process, reschedule the handler + m_io.post([this, h, repeat]() { + (*this->shared_from_this())(h, boost::asio::error::operation_aborted, repeat); + }); + } else if (repeat > std::chrono::milliseconds(0)) { + m_timer.expires_from_now(repeat); + m_timer.async_wait( + [this, h, repeat] + (const boost::system::error_code& ec) { + (*this->shared_from_this())(h, ec, repeat); + }); } } - - m_wait_handler = nullptr; } // Called by io_service on timeout of m_timer - void operator() (const system::error_code& ec) { - process_queue(ec); - } - - // Called by io_service in response to enqueue(T&) - void operator() () { - process_queue(system::error_code()); + void operator() (async_handler h, const boost::system::error_code& ec, + std::chrono::milliseconds repeat) { + process_queue(h, repeat); } public: - concurrent_queue(boost::asio::io_service& a_io, - int a_batch_size = 1, const Alloc& a_alloc = Alloc()) + async_queue(boost::asio::io_service& a_io, + int a_batch_size = 16, const Alloc& a_alloc = Alloc()) : m_io(a_io) - , m_queue(255, a_alloc) + , m_queue(a_alloc) , m_batch_size(a_batch_size) , m_timer(a_io) , m_is_canceled(false) {} + ~async_queue() { + reset(); + } + void reset() { m_is_canceled = true; T value; while (m_queue.pop(value)); - if (m_wait_handler != nullptr) - m_io.post([this]() { (*this)(s_operation_canceled); }); - + m_timer.cancel(); m_is_canceled = false; } bool canceled() const { return m_is_canceled; } - bool enqueue(T const& data) { + bool enqueue(T const& data, bool notify = true) { if (m_is_canceled) return false; if (!m_queue.push(data)) return false; - if (m_wait_handler != nullptr) - m_io.post(*this); + if (!notify) return true; + + m_timer.cancel(); + + return true; } - bool dequeue(T& value, const async_handler& a_on_data, - std::chrono::milliseconds a_wait_duration = -1) - { - if (m_queue.pop(value)) - return true; - else if (a_wait_duration.count() == 0) - return false; + bool dequeue(T& value) { + if (m_is_canceled) return false; + return m_queue.pop(value); + } - if (m_waiter_handler != nullptr) - throw std::runtime_error("Another waiting operation in progress!"); - m_wait_handler = a_on_data; + bool async_dequeue(async_handler a_on_data, + std::chrono::milliseconds a_wait_duration = std::chrono::milliseconds(-1), + bool repeat = false) + { + if (m_is_canceled) return false; + T value; if (m_queue.pop(value)) { - m_wait_handler = nullptr; + a_on_data(value, boost::system::error_code()); return true; - } - - if (a_wait_duration.count() < 0 || m_is_canceled) + } else if (a_wait_duration == std::chrono::milliseconds(0)) return false; - m_timer.expires_from_now(a_wait_duration); - m_timer.async_wait([this]() { - (*this)(boost::asio::error::make_error_code(boost::asio::error::timeout)); - }); + m_timer.cancel(); + std::chrono::milliseconds timeout = + a_wait_duration < std::chrono::milliseconds(0) + ? std::chrono::milliseconds::max() + : a_wait_duration; + + auto repeat_msec = repeat ? timeout : std::chrono::milliseconds(0); + m_timer.expires_from_now(timeout); + m_timer.async_wait( + [this, &a_on_data, repeat_msec] + (const boost::system::error_code& ec) { + (*this)(a_on_data, ec, repeat_msec); + } + ); return false; } + + void cancel_async() { m_timer.cancel(); } }; } // namespace util diff --git a/include/eixx/util/async_wait_timeout.hpp b/include/eixx/util/async_wait_timeout.hpp index f1e0429..0c4bd1d 100644 --- a/include/eixx/util/async_wait_timeout.hpp +++ b/include/eixx/util/async_wait_timeout.hpp @@ -2,7 +2,9 @@ #define _ASYNC_WAIT_TIMEOUT_HPP_ #include +#include +namespace boost { namespace asio { class deadline_timer_ex : public basic_deadline_timer @@ -52,8 +54,7 @@ namespace asio { } }; - } // namespace asio - +} // namespace asio } // namespace boost #endif // _ASYNC_WAIT_TIMEOUT_HPP_ diff --git a/include/eixx/util/timeout.hpp b/include/eixx/util/timeout.hpp index 15d3e93..6e792d1 100644 --- a/include/eixx/util/timeout.hpp +++ b/include/eixx/util/timeout.hpp @@ -4,7 +4,6 @@ #include namespace boost { - namespace asio { namespace error { @@ -46,5 +45,6 @@ namespace system { }; } // namespace system +} // namespace boost #endif // _EIXX_TIMEOUT_HPP_ diff --git a/test/Makefile.am b/test/Makefile.am index e79e43a..c0884d2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,24 +1,32 @@ -bin_PROGRAMS = test_eterm test_perf +bin_PROGRAMS = test_eterm test_perf test_connect AM_CXXFLAGS = -I. -I$(srcdir)/../include $(BOOST_CPPFLAGS) \ -I$(ERLANG_LIB_DIR_erl_interface)/include \ -I$(ERLANG_LIB_DIR_erl_interface)/src -test_eterm_SOURCES = test_eterm.cpp test_eterm_encode.cpp \ - test_eterm_format.cpp test_eterm_match.cpp \ - test_eterm_pool.cpp test_eterm_refc.cpp \ - test_mailbox.cpp test_node.cpp -test_eterm_CPPFLAGS = -DBOOST_TEST_DYN_LINK -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ - $(if $(debug),-DEIXX_DEBUG) -test_eterm_LDFLAGS = $(BOOST_LDFLAGS) \ - -L$(ERLANG_LIB_DIR_erl_interface)/lib -test_eterm_LDADD = -L../src/.libs -leixx -lei \ - $(BOOST_SYSTEM_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) \ - $(BOOST_THREAD_LIB) +test_eterm_SOURCES = test_eterm.cpp test_eterm_encode.cpp \ + test_eterm_format.cpp test_eterm_match.cpp \ + test_eterm_pool.cpp test_eterm_refc.cpp \ + test_mailbox.cpp test_node.cpp +test_eterm_CPPFLAGS = -DBOOST_TEST_DYN_LINK -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ + $(if $(debug),-DEIXX_DEBUG) +test_eterm_LDFLAGS = $(BOOST_LDFLAGS) \ + -L$(ERLANG_LIB_DIR_erl_interface)/lib +test_eterm_LDADD = -L../src/.libs -leixx -lei \ + $(BOOST_SYSTEM_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) \ + $(BOOST_THREAD_LIB) -test_perf_SOURCES = test_perf.cpp -test_perf_CPPFLAGS = -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) -test_perf_LDFLAGS = -L$(ERLANG_LIB_DIR_erl_interface)/lib $(BOOST_LDFLAGS) -test_perf_LDADD = -L../src/.libs -leixx $(BOOST_SYSTEM_LIB) +test_connect_SOURCES = test_async_queue.cpp +test_connect_CPPFLAGS = -DBOOST_TEST_DYN_LINK -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ + $(if $(debug),-DEIXX_DEBUG) +test_connect_LDFLAGS = $(BOOST_LDFLAGS) +test_connect_LDADD = -L../src/.libs -leixx \ + $(BOOST_SYSTEM_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) \ + $(BOOST_THREAD_LIB) + +test_perf_SOURCES = test_perf.cpp +test_perf_CPPFLAGS = -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) +test_perf_LDFLAGS = -L$(ERLANG_LIB_DIR_erl_interface)/lib $(BOOST_LDFLAGS) +test_perf_LDADD = -L../src/.libs -leixx $(BOOST_SYSTEM_LIB) From deafc8d2832ace8e9c4fba19c5d29f23b54ea0b9 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 15 Oct 2013 00:16:22 -0400 Subject: [PATCH 010/185] Added ASIO waitable queue --- .gitignore | 1 + .../connect/transport_otp_connection_tcp.hpp | 2 +- include/eixx/util/async_queue.hpp | 116 +++++++----- test/test_async_queue.cpp | 171 ++++++++++++++++++ 4 files changed, 243 insertions(+), 47 deletions(-) create mode 100644 test/test_async_queue.cpp diff --git a/.gitignore b/.gitignore index 16ceb2f..19928a5 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ test/Makefile.in test/test_eterm test/*.o test/test_perf +test/test_connect diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 560ae94..24e7637 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -81,7 +81,7 @@ class tcp_connection { public: typedef connection base_t; - + tcp_connection(boost::asio::io_service& a_svc, Handler* a_h, const Alloc& a_alloc) : connection(TCP, a_svc, a_h, a_alloc) , m_socket(a_svc) diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index be34400..8652478 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include #include #include #include @@ -57,7 +58,7 @@ struct async_queue : std::enable_shared_from_this> { typedef boost::lockfree::queue< T, boost::lockfree::allocator, - boost::lockfree::capacity<255> + boost::lockfree::capacity<256> > queue_type; typedef std::function< @@ -70,52 +71,65 @@ struct async_queue : std::enable_shared_from_this> boost::asio::system_timer m_timer; bool m_is_canceled; + int dec_repeat_count(int n) { + return n == std::numeric_limits::max() || !n ? n : n-1; + } + // Dequeue up to m_batch_size of items and for each one call // m_wait_handler - void process_queue(async_handler h, std::chrono::milliseconds repeat) { - if (h == nullptr) return; + void process_queue(const async_handler& h, const boost::system::error_code& ec, + std::chrono::milliseconds repeat, int repeat_count) { + if (h == nullptr || m_is_canceled) return; // Process up to m_batch_size items waiting on the queue. // For each dequeued item call m_wait_handler int i = 0; // Number of handler invocations - bool canceled = m_is_canceled; + bool canceled = ec; - if (!canceled) - for (; i < m_batch_size; i++) { - T value; - if (m_queue.pop(value)) - if (!h(value, boost::system::error_code())) // If handler returns false - break - break; + T value; + while (i < m_batch_size && m_queue.pop(value)) { + i++; + repeat_count = dec_repeat_count(repeat_count); + if (!h(value, boost::system::error_code())) { + canceled = true; + break; } + } - // If we haven't processed any data and the operation was canceled - // invoke the callback to see if we need to remove the handler - if (!i && canceled) { + // If we reached the batch size and queue has more data + // to process - give up the time slice and reschedule the handler + if (i == m_batch_size && !m_queue.empty()) { + m_io.post([this, h, repeat, repeat_count]() { + (*this->shared_from_this())( + h, boost::asio::error::operation_aborted, repeat, repeat_count); + }); + } else if (!i && canceled) { + // If we haven't processed any data and the timer was canceled. + // Invoke the callback to see if we need to remove the handler. T dummy; - h(dummy, boost::asio::error::eof); - } else if (!canceled) { - if (i == m_batch_size && !m_queue.empty()) { - // There's more data to process, reschedule the handler - m_io.post([this, h, repeat]() { - (*this->shared_from_this())(h, boost::asio::error::operation_aborted, repeat); + if (!h(dummy, ec)) + return; + } + + int n = dec_repeat_count(repeat_count); + + // If requested repeated timer, schedule new timer invocation + if (repeat > std::chrono::milliseconds(0) && n > 0) { + m_timer.expires_from_now(repeat); + m_timer.async_wait( + [this, h, repeat, n] + (const boost::system::error_code& ec) { + (*this->shared_from_this())(h, ec, repeat, n); }); - } else if (repeat > std::chrono::milliseconds(0)) { - m_timer.expires_from_now(repeat); - m_timer.async_wait( - [this, h, repeat] - (const boost::system::error_code& ec) { - (*this->shared_from_this())(h, ec, repeat); - }); - } } } // Called by io_service on timeout of m_timer - void operator() (async_handler h, const boost::system::error_code& ec, - std::chrono::milliseconds repeat) { - process_queue(h, repeat); + void operator() (const async_handler& h, const boost::system::error_code& ec, + std::chrono::milliseconds repeat, int repeat_count) { + process_queue(h, ec, repeat, repeat_count); } public: @@ -133,14 +147,20 @@ struct async_queue : std::enable_shared_from_this> } void reset() { - m_is_canceled = true; + cancel(); + T value; while (m_queue.pop(value)); - m_timer.cancel(); m_is_canceled = false; } + void cancel() { + m_is_canceled = true; + boost::system::error_code ec; + m_timer.cancel(ec); + } + bool canceled() const { return m_is_canceled; } bool enqueue(T const& data, bool notify = true) { @@ -151,7 +171,8 @@ struct async_queue : std::enable_shared_from_this> if (!notify) return true; - m_timer.cancel(); + boost::system::error_code ec; + m_timer.cancel(ec); return true; } @@ -161,38 +182,41 @@ struct async_queue : std::enable_shared_from_this> return m_queue.pop(value); } - bool async_dequeue(async_handler a_on_data, + bool async_dequeue(const async_handler& a_on_data, int repeat_count = 0) { + return async_dequeue(a_on_data, std::chrono::milliseconds(-1), repeat_count); + } + + bool async_dequeue(const async_handler& a_on_data, std::chrono::milliseconds a_wait_duration = std::chrono::milliseconds(-1), - bool repeat = false) + int repeat_count = 0) { if (m_is_canceled) return false; T value; - if (m_queue.pop(value)) { - a_on_data(value, boost::system::error_code()); - return true; - } else if (a_wait_duration == std::chrono::milliseconds(0)) + if (m_queue.pop(value)) + return a_on_data(value, boost::system::error_code()); + else if (a_wait_duration == std::chrono::milliseconds(0)) return false; - m_timer.cancel(); std::chrono::milliseconds timeout = a_wait_duration < std::chrono::milliseconds(0) ? std::chrono::milliseconds::max() : a_wait_duration; - auto repeat_msec = repeat ? timeout : std::chrono::milliseconds(0); + auto rep = repeat_count < 0 ? std::numeric_limits::max() : repeat_count; + auto repeat_msec = rep > 0 ? timeout : std::chrono::milliseconds(0); + boost::system::error_code ec; + m_timer.cancel(ec); m_timer.expires_from_now(timeout); m_timer.async_wait( - [this, &a_on_data, repeat_msec] - (const boost::system::error_code& ec) { - (*this)(a_on_data, ec, repeat_msec); + [this, &a_on_data, repeat_msec, rep] + (const boost::system::error_code& e) { + (*this->shared_from_this())(a_on_data, e, repeat_msec, rep); } ); return false; } - - void cancel_async() { m_timer.cancel(); } }; } // namespace util diff --git a/test/test_async_queue.cpp b/test/test_async_queue.cpp new file mode 100644 index 0000000..b974d43 --- /dev/null +++ b/test/test_async_queue.cpp @@ -0,0 +1,171 @@ +//---------------------------------------------------------------------------- +/// \file test_mailbox.cpp +//---------------------------------------------------------------------------- +/// \brief Test cases for basic_otp_mailbox. +//---------------------------------------------------------------------------- +// Copyright (c) 2010 Serge Aleynikov +// Created: 2010-09-23 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the EPI (Erlang Plus Interface) Library. + +Copyright (C) 2010 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ + +#define BOOST_TEST_MODULE test_async_queue + +//#define BOOST_ASIO_ENABLE_HANDLER_TRACKING + +#include +#include +#include +#include +#include +#include + +using namespace eixx::util; + +int b, n, i; + +BOOST_AUTO_TEST_CASE( test_async_queue ) +{ + boost::asio::io_service io; + + std::shared_ptr> q(new async_queue(io)); + + bool res = q->async_dequeue( + [](int& a, const boost::system::error_code& ec) { i = a; return false; }, + std::chrono::milliseconds(0)); + + BOOST_REQUIRE(!res); + + for (i = 10; i < 13; i++) + BOOST_REQUIRE(q->enqueue(i)); + + for (int j = 10; j < 13; j++) { + BOOST_REQUIRE(q->async_dequeue( + [j](int& a, const boost::system::error_code& ec) { + BOOST_REQUIRE_EQUAL(j, a); + return true; + }, + std::chrono::milliseconds(0))); + } + + b = 15; + bool r = q->async_dequeue( + [](int& a, const boost::system::error_code& ec) { + BOOST_REQUIRE_EQUAL(b++, a); + n++; + return true; + }, 3); + BOOST_REQUIRE(!r); + + i = 15; + + BOOST_REQUIRE(q->enqueue(i++)); + BOOST_REQUIRE(q->enqueue(i++)); + BOOST_REQUIRE(q->enqueue(i++)); + + io.run(); + + BOOST_REQUIRE_EQUAL(i, b); + BOOST_REQUIRE_EQUAL(3, n); +} + +namespace { + const int iterations = getenv("ITERATIONS") ? atoi("ITERATIONS") : 1000000; + + std::atomic_int producer_count(0); + std::atomic_int consumer_count(0); + + const int producer_thread_count = 4; + std::atomic_int done_producer_count(0); + + int total_iterations = producer_thread_count * iterations; + + std::atomic done (false); +} + +void producer(async_queue& q, std::atomic_int& n, int i) +{ + for (int i = 0; i != iterations; ++i) { + int value = ++n; + while (!q.enqueue(value)); + } + + if (eixx::verboseness::level() >= eixx::connect::VERBOSE_DEBUG) + std::cout << "Producer thread " << i << " done" << std::endl; + + done = ++done_producer_count == producer_thread_count; +} + +BOOST_AUTO_TEST_CASE( test_async_queue_concurrent ) +{ + boost::asio::io_service io; + + std::shared_ptr> q(new async_queue(io, 128)); + + boost::thread_group producer_threads; + + for (int i = 0; i < producer_thread_count; ++i) + producer_threads.create_thread( + [&q, i] () { producer(*q, producer_count, i+1); } + ); + + while (q->async_dequeue( + [] (int& v, const boost::system::error_code& ec) { + consumer_count++; + return consumer_count < total_iterations; + }, + std::chrono::milliseconds(1000), + true)); + + io.run(); + io.reset(); + + producer_threads.join_all(); + + if (eixx::verboseness::level() >= eixx::connect::VERBOSE_DEBUG) { + std::cout << "Produced " << producer_count << " objects." << std::endl; + std::cout << "Consumed " << consumer_count << " objects." << std::endl; + } + + auto r = q->async_dequeue( + [] (int& v, const boost::system::error_code& ec) { return true; }, + std::chrono::milliseconds(8000), + -1); + + BOOST_REQUIRE(!r); + + boost::asio::system_timer t(io); + t.expires_from_now(std::chrono::milliseconds(1)); + t.async_wait([&q](const boost::system::error_code& e) { + q->cancel(); + if (eixx::verboseness::level() >= eixx::connect::VERBOSE_DEBUG) + std::cout << "Canceled timer" << std::endl; + }); + + io.run(); + + if (eixx::verboseness::level() >= eixx::connect::VERBOSE_DEBUG) + std::cout << "Done!" << std::endl; +} + From acd70c50eb187637a4d519db5a0a2b92381891f7 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 16 Oct 2013 15:38:09 -0400 Subject: [PATCH 011/185] Work in progress --- include/eixx/connect/basic_otp_mailbox.hpp | 200 ++++++++++-------- .../connect/basic_otp_mailbox_registry.hpp | 53 +++-- include/eixx/connect/basic_otp_node.hpp | 6 +- include/eixx/connect/transport_msg.hpp | 20 +- include/eixx/marshal/atom.hpp | 2 +- include/eixx/namespace.hpp | 39 ++++ include/eixx/util/async_queue.hpp | 39 ++-- test/test_async_queue.cpp | 12 +- 8 files changed, 227 insertions(+), 144 deletions(-) create mode 100644 include/eixx/namespace.hpp diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index 9b601a5..78e2365 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include +#include #include #include #include @@ -90,11 +91,13 @@ class basic_otp_mailbox public: typedef std::shared_ptr > pointer; - typedef boost::function< - void (basic_otp_mailbox&, boost::system::error_code&) + typedef std::function< + void (basic_otp_mailbox&, + transport_msg*&, + ::boost::system::error_code&) > receive_handler_type; - typedef std::list*> queue_type; + typedef util::async_queue*, Alloc> queue_type; private: boost::asio::io_service& m_io_service; @@ -103,26 +106,25 @@ class basic_otp_mailbox atom m_name; std::set > m_links; std::map, epid > m_monitors; - queue_type m_queue; - boost::asio::deadline_timer_ex m_deadline_timer; + std::shared_ptr m_queue; std::chrono::time_point< - std::chrono::system_clock> m_free_time; // Cache time of this mbox - boost::function< - void (receive_handler_type f, - boost::system::error_code&)> m_deadline_handler; + std::chrono::system_clock> m_time_freed; // Cache time of this mbox + receive_handler_type m_handler; // Called on async_receive void do_deliver(transport_msg* a_msg); - void do_on_deadline_timer(receive_handler_type f, boost::system::error_code& ec); + bool operator() (transport_msg*& a_msg, const boost::system::error_code& ec); public: basic_otp_mailbox( basic_otp_node& a_node, const epid& a_self, - const atom& a_name = atom(), boost::asio::io_service* a_svc = NULL) + const atom& a_name = atom(), int a_queue_size = 255, + boost::asio::io_service* a_svc = NULL, const Alloc& a_alloc = Alloc()) : m_io_service(a_svc ? *a_svc : a_node.io_service()) , m_node(a_node), m_self(a_self) , m_name(a_name) - , m_deadline_timer(m_io_service) + , m_queue(new queue_type(m_io_service, a_queue_size, a_alloc)) + , m_time_freed(std::chrono::microseconds(0)) {} ~basic_otp_mailbox() { @@ -131,12 +133,7 @@ class basic_otp_mailbox /// @param a_reg_remove when true the mailbox's pid is removed from registry. /// Only pass false when invoking from the registry on destruction. - void close(const eterm& a_reason = am_normal, bool a_reg_remove = true) { - m_deadline_timer.cancel(); - if (a_reg_remove) - m_node.close_mailbox(this); - break_links(a_reason); - } + void close(const eterm& a_reason = am_normal, bool a_reg_remove = true); basic_otp_node& node() const { return m_node; } /// Pid associated with this mailbox. @@ -145,20 +142,24 @@ class basic_otp_mailbox const atom& name() const { return m_name; } boost::asio::io_service& io_service() const { return m_io_service; } /// Queue of pending received messages. - queue_type& queue() { return m_queue; } + //queue_type& queue() { return m_queue; } /// Indicates if mailbox doesn't have any pending messages bool empty() const { return m_queue.empty(); } - void name(const atom& a_name) { m_name = a_name; } + void register(const atom& a_name) { + if (m_node. + m_name = a_name; + + } bool operator== (const basic_otp_mailbox& rhs) const { return self() == rhs.self(); } bool operator!= (const basic_otp_mailbox& rhs) const { return self() != rhs.self(); } - std::ostream& dump(std::ostream& out) const { - out << "#Mbox{pid=" << self(); - if (m_name != atom()) out << ", name=" << m_name; - return out << '}'; - } + /// Clear mailbox's queue of awaiting messages + void clear() { m_queue->reset(); } + + /// Print pid and regname of the mailbox to the given stream + std::ostream& dump(std::ostream& out) const; /// Find the first message in the mailbox matching a pattern. /// Return the message, and if \a a_binding is not NULL set the binding variables. @@ -170,19 +171,52 @@ class basic_otp_mailbox /// Dequeue the next message from the mailbox. The call is non-blocking and /// returns NULL if no messages are waiting. transport_msg* receive() { - if (m_queue.empty()) - return NULL; - transport_msg* p = m_queue.front(); - m_queue.pop_front(); - return p; + transport_msg* m; + return m_queue->dequeue(m) ? m : nullptr; + } + + /** + * Call a handler on asynchronous delivery of message(s). + * + * The call is non-blocking. If returns Upon timeout + * or delivery of a message to the mailbox the handler \a h will be + * invoked. The handler must have a signature with two arguments: + * \verbatim + * void handler(basic_otp_mailbox& a_mailbox, + * transport_msg*& a_msg, + * ::boost::system::error_code& a_errc); + * \endverbatim + * In case of timeout the error will be set to non-zero value + * + * @param h is the handler to call upon arrival of a message + * @param a_timeout is the timeout interval to wait for message (-1 = infinity) + * @param a_repeat_count is the number of messages to wait (-1 = infinite) + * @return true if the message was synchronously received + **/ + bool async_receive(receive_handler_type h, + std::chrono::milliseconds a_timeout = std::chrono::milliseconds(-1), + int a_repeat_count = 0 + ) + throw (std::runtime_error); + + /** + * Cancel pending asynchronous receive operation + */ + void cancel_async_receive() { + m_handler = nullptr; + m_queue->cancel(); } /// Deliver a message to this mailbox. The call is thread-safe. void deliver(const transport_msg& a_msg) { - transport_msg* l_msg = new transport_msg(a_msg); - m_io_service.post( - std::bind( - &basic_otp_mailbox::do_deliver, this, l_msg)); + transport_msg* p = new transport_msg(a_msg); + m_queue->enqueue(p); + } + + /// Deliver a message to this mailbox. The call is thread-safe. + void deliver(transport_msg&& a_msg) { + transport_msg* p = new transport_msg(std::move(a_msg)); + m_queue->enqueue(p); } /// Send a message \a a_msg to a pid \a a_to. @@ -198,26 +232,6 @@ class basic_otp_mailbox m_node.send(self(), a_node, a_to, a_msg); } - /** - * Get a message from this mailbox. The call is non-blocking. Upon timeout - * or delivery of a message to the mailbox the handler \a h will be - * invoked. The handler must have a signature with two arguments: - * \verbatim - * void handler(transport_msg& a_msg, boost::system::error_code& ec); - * \endverbatim - * In case of timeout the error will be set to: asio::error::timeout - * that is defined in eixx/util/async_wait_timeout.hpp. - **/ - void async_receive(receive_handler_type h, long msec_timeout = -1) - throw (std::runtime_error); - - /** - * Cancel pending asynchronous receive operation - */ - void cancel_async_receive() { - m_deadline_timer.cancel(); - } - /** * Block until response for a RPC call arrives. * @return a pointer to ErlTerm containing the response @@ -306,6 +320,41 @@ class basic_otp_mailbox // basic_otp_mailbox implementation //------------------------------------------------------------------------------ +template +void basic_otp_mailbox:: +close(const eterm& a_reason = am_normal, bool a_reg_remove = true) { + m_handler = nullptr; + m_queue->reset(); + m_time_freed = std::chrono::system_clock::now(); + if (a_reg_remove) + m_node.close_mailbox(this); + break_links(a_reason); + m_name = atom(); +} + +template +bool basic_otp_mailbox:: +operator() (transport_msg*& a_msg, const boost::system::error_code& ec) +{ + if (m_time_freed != std::chrono::microseconds(0) || !m_handler) + return false; + m_handler(*this, a_msg, ec); + if (a_msg) { + delete a_msg; + a_msg = NULL; + } + return true; +} + +template +bool basic_otp_mailbox:: +async_receive(receive_handler_type h, std::chrono::milliseconds a_timeout, + int a_repeat_count) throw (std::runtime_error) +{ + m_handler = h; + return m_queue->async_dequeue(*this, a_timeout, a_repeat_count); +} + template void basic_otp_mailbox:: break_links(const eterm& a_reason) @@ -338,41 +387,6 @@ match(const eterm& a_pattern, varbind* a_binding) return NULL; } -template -void basic_otp_mailbox:: -do_on_deadline_timer(receive_handler_type f, boost::system::error_code& ec) -{ - m_deadline_timer.expires_at(boost::asio::deadline_timer_ex::time_type()); - - f(*this, ec); // In case of timeout ec would contain boost::asio::error::timeout -} - -template -void basic_otp_mailbox:: -async_receive(receive_handler_type h, long msec_timeout) throw (std::runtime_error) -{ - m_deadline_timer.cancel(); - - // expires_at() == boost::posix_time::not_a_date_time - /* - if (m_deadline_timer.expires_at() != boost::asio::deadline_timer_ex::time_type()) - throw eterm_exception( - "Another receive() is already scheduled for mailbox", self()); - */ - - if (msec_timeout < 0) - m_deadline_timer.async_wait( - std::bind( - &basic_otp_mailbox::do_on_deadline_timer, - this, h, std::placeholders::_1)); - else - m_deadline_timer.async_wait_timeout( - std::bind( - &basic_otp_mailbox::do_on_deadline_timer, - this, h, std::placeholders::_1), - msec_timeout); -} - template void basic_otp_mailbox:: do_deliver(transport_msg* a_msg) @@ -432,6 +446,14 @@ do_deliver(transport_msg* a_msg) m_deadline_timer.cancel(); } +template +std::ostream& basic_otp_mailbox:: +dump(std::ostream& out) const { + out << "#Mbox{pid=" << self(); + if (m_name != atom()) out << ", name=" << m_name; + return out << '}'; +} + } // namespace connect } // namespace EIXX_NAMESPACE diff --git a/include/eixx/connect/basic_otp_mailbox_registry.hpp b/include/eixx/connect/basic_otp_mailbox_registry.hpp index a35f130..d042905 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.hpp +++ b/include/eixx/connect/basic_otp_mailbox_registry.hpp @@ -74,10 +74,10 @@ class basic_otp_mailbox_registry { void clear(); - bool add(const atom& a_name, mailbox_ptr a_mbox); + bool add(atom a_name, mailbox_ptr a_mbox); /// Unregister a name so that no mailbox is any longer associated with \a a_name. - bool unregister(const atom& a_name); + bool erase(const atom& a_name); /// Remove \a a_mbox mailbox from the registry void erase(mailbox_ptr a_mbox); @@ -94,7 +94,7 @@ class basic_otp_mailbox_registry { * don't find it again. */ mailbox_ptr - get(const atom& a_name) const throw(err_no_process); + get(atom a_name) const throw(err_no_process); /** * Look up a mailbox based on its pid. If the mailbox has gone out @@ -121,8 +121,8 @@ class basic_otp_mailbox_registry { template typename basic_otp_mailbox_registry::mailbox_ptr -basic_otp_mailbox_registry::create_mailbox( - const atom& a_name, boost::asio::io_service* a_svc) +basic_otp_mailbox_registry:: +create_mailbox(const atom& a_name, boost::asio::io_service* a_svc) { lock_guard guard(m_lock); if (!a_name.empty()) { @@ -140,53 +140,56 @@ basic_otp_mailbox_registry::create_mailbox( } template -void basic_otp_mailbox_registry::clear() +void basic_otp_mailbox_registry:: +clear() { if (!m_by_name.empty() || !m_by_pid.empty()) { - static const atom s_am_normal("normal"); lock_guard guard(m_lock); m_by_name.clear(); typename std::map, mailbox_ptr>::iterator it; for(it = m_by_pid.begin(); it != m_by_pid.end(); ++it) { mailbox_ptr p = it->second; - p->close(s_am_normal, false); + p->close(am_normal, false); } m_by_pid.clear(); } } template -bool basic_otp_mailbox_registry::add(const atom& a_name, mailbox_ptr a_mbox) +bool basic_otp_mailbox_registry:: +add(atom a_name, mailbox_ptr a_mbox) { if (a_name.empty()) throw err_bad_argument("Empty registering name!"); if (!a_mbox->name().empty()) throw err_bad_argument("Mailbox already registered as", a_mbox->name()); lock_guard guard(m_lock); - if (m_by_name.find(a_name) != m_by_name.end()) - return false; - m_by_name.insert(std::pair(a_name, a_mbox)); - a_mbox->name(a_name); - return true; + auto it = m_by_name.insert(std::pair(a_name, a_mbox)); + if (it.second) + a_mbox->name(a_name); + return it.second; } /// Unregister a name so that no mailbox is any longer associated with \a a_name. template -bool basic_otp_mailbox_registry::unregister(const atom& a_name) +bool basic_otp_mailbox_registry:: +erase(atom a_name) { if (!a_name.empty()) return false; lock_guard guard(m_lock); typename std::map::iterator it = m_by_name.find(a_name); if (it == m_by_name.end()) - return; - it->second.name(""); + return false; + it->second.name(atom()); m_by_name.erase(it); + return true; } /// Remove \a a_mbox mailbox from the registry template -void basic_otp_mailbox_registry::erase(mailbox_ptr a_mbox) +void basic_otp_mailbox_registry:: +erase(mailbox_ptr a_mbox) { if (!a_mbox) return; @@ -194,7 +197,7 @@ void basic_otp_mailbox_registry::erase(mailbox_ptr a_mbox) m_by_pid.erase(a_mbox->self()); if (!a_mbox->name().empty()) m_by_name.erase(a_mbox->name()); - a_mbox->name(""); + a_mbox->name(atom()); } /** @@ -202,8 +205,8 @@ void basic_otp_mailbox_registry::erase(mailbox_ptr a_mbox) */ template typename basic_otp_mailbox_registry::mailbox_ptr -basic_otp_mailbox_registry::get(const eterm& a_proc) const - throw (err_bad_argument, err_no_process) +basic_otp_mailbox_registry:: +get(const eterm& a_proc) const throw (err_bad_argument, err_no_process) { switch (a_proc.type()) { case ATOM: return get(a_proc.to_atom()); @@ -219,8 +222,8 @@ basic_otp_mailbox_registry::get(const eterm& a_proc) const */ template typename basic_otp_mailbox_registry::mailbox_ptr -basic_otp_mailbox_registry::get(const atom& a_name) const - throw(err_no_process) +basic_otp_mailbox_registry:: +get(atom a_name) const throw(err_no_process) { lock_guard guard(m_lock); typename std::map::iterator it = m_by_name.find(a_name); @@ -249,7 +252,9 @@ basic_otp_mailbox_registry::get(const epid& a_pid) const template void basic_otp_mailbox_registry::names(std::list& list) { + list.clear(); lock_guard guard(m_lock); + list.resize(m_by_name.size()); for(typename std::map::const_iterator it = m_by_name.begin(), end = m_by_name.end(); it != end; ++it) list.push_back(it->first); @@ -258,7 +263,9 @@ void basic_otp_mailbox_registry::names(std::list& list) template void basic_otp_mailbox_registry::pids(std::list >& list) { + list.clear(); lock_guard guard(m_lock); + list.resize(m_by_pid.size()); for(typename std::map, mailbox_ptr>::const_iterator it = m_by_pid.begin(), end = m_by_pid.eend(); it != end; ++it) list.push_back(it->first); diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index 0146e43..221f392 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -226,13 +226,15 @@ class basic_otp_node: public basic_otp_node_local { /// Get a mailbox registered by a given atom name. basic_otp_mailbox* - get_mailbox(const atom& a_name) const { return m_mailboxes.get(a_name); } + get_mailbox(atom a_name) const { return m_mailboxes.get(a_name); } /// Get a mailbox registered by a given epid. basic_otp_mailbox* get_mailbox(const epid& a_pid) const { return m_mailboxes.get(a_pid); } - const mailbox_registry_t& registry() const { return m_mailboxes; } + const mailbox_registry_t& registry() const { return m_mailboxes; } + + bool register_mailbox(atom a_name) /// Create a new unique pid epid create_pid(); diff --git a/include/eixx/connect/transport_msg.hpp b/include/eixx/connect/transport_msg.hpp index fc9b0cc..a63b2e0 100644 --- a/include/eixx/connect/transport_msg.hpp +++ b/include/eixx/connect/transport_msg.hpp @@ -76,6 +76,14 @@ class transport_msg { , NO_EXCEPTION_MASK = (uint32_t)EXCEPTION-1 }; +private: + // Note that the m_type is mutable so that we can call set_error_flag() on + // constant objects. + mutable transport_msg_type m_type; + tuple m_cntrl; + eterm m_msg; + +public: transport_msg() : m_type(UNDEFINED) {} transport_msg(int a_msgtype, const tuple& a_cntrl, const eterm* a_msg = NULL) @@ -89,6 +97,12 @@ class transport_msg { : m_type(rhs.m_type), m_cntrl(rhs.m_cntrl), m_msg(rhs.m_msg) {} + transport_msg(transport_msg&& rhs) + : m_type(rhs.m_type), m_cntrl(std::move(rhs.m_cntrl)), m_msg(std::move(rhs.m_msg)) + { + rhs.m_type = UNDEFINED; + } + /// Return a string representation of the transport message type. const char* type_string() const; @@ -386,12 +400,6 @@ class transport_msg { } private: - // Note that the m_type is mutable so that we can call set_error_flag() on - // constant objects. - mutable transport_msg_type m_type; - tuple m_cntrl; - eterm m_msg; - void set_exit_internal(int a_type, int a_trace_type, const epid& a_from, const epid& a_to, const eterm& a_reason, const Alloc& a_alloc = Alloc()) diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index ed69572..e3add7e 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -114,7 +114,7 @@ class atom /// Copy atom from another atom. This is a constant time /// SMP safe operation. - atom(const atom& s) throw() : m_index(s.m_index) {} + atom(atom s) throw() : m_index(s.m_index) {} /// Decode an atom from a binary buffer encoded in /// Erlang external binary format. diff --git a/include/eixx/namespace.hpp b/include/eixx/namespace.hpp new file mode 100644 index 0000000..84d98df --- /dev/null +++ b/include/eixx/namespace.hpp @@ -0,0 +1,39 @@ +//---------------------------------------------------------------------------- +/// \file namespace.hpp +//---------------------------------------------------------------------------- +/// \brief Header file for defining eixx namespace name +//---------------------------------------------------------------------------- +// Copyright (c) 2010 Serge Aleynikov +// Created: 2010-09-20 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the eixx (Erlang C++ Interface) Library. + +Copyright (C) 2010 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ +#ifndef _EIXX_NAMESPACE_HPP_ +#define _EIXX_NAMESPACE_HPP_ + +#ifndef EIXX_NAMESPACE +#define EIXX_NAMESPACE eixx +#endif + +#endif diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index 8652478..54e6556 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -69,7 +69,6 @@ struct async_queue : std::enable_shared_from_this> queue_type m_queue; int m_batch_size; boost::asio::system_timer m_timer; - bool m_is_canceled; int dec_repeat_count(int n) { return n == std::numeric_limits::max() || !n ? n : n-1; @@ -79,7 +78,7 @@ struct async_queue : std::enable_shared_from_this> // m_wait_handler void process_queue(const async_handler& h, const boost::system::error_code& ec, std::chrono::milliseconds repeat, int repeat_count) { - if (h == nullptr || m_is_canceled) return; + if (h == nullptr) return; // Process up to m_batch_size items waiting on the queue. // For each dequeued item call m_wait_handler @@ -139,7 +138,6 @@ struct async_queue : std::enable_shared_from_this> , m_queue(a_alloc) , m_batch_size(a_batch_size) , m_timer(a_io) - , m_is_canceled(false) {} ~async_queue() { @@ -151,21 +149,17 @@ struct async_queue : std::enable_shared_from_this> T value; while (m_queue.pop(value)); - - m_is_canceled = false; } - void cancel() { - m_is_canceled = true; + int batch_size() const { return m_batch_size; } + void batch_size(int sz) { m_batch_size = sz; } + + bool cancel() { boost::system::error_code ec; - m_timer.cancel(ec); + return m_timer.cancel(ec); } - bool canceled() const { return m_is_canceled; } - bool enqueue(T const& data, bool notify = true) { - if (m_is_canceled) return false; - if (!m_queue.push(data)) return false; @@ -178,25 +172,32 @@ struct async_queue : std::enable_shared_from_this> } bool dequeue(T& value) { - if (m_is_canceled) return false; return m_queue.pop(value); } + /// Call \a a_on_data handler asyncronously on next message in the queue. + /// + /// @returns true if the call was handled synchronously bool async_dequeue(const async_handler& a_on_data, int repeat_count = 0) { return async_dequeue(a_on_data, std::chrono::milliseconds(-1), repeat_count); } + /// Call \a a_on_data handler asyncronously on next message in the queue. + /// + /// @returns true if the call was handled synchronously bool async_dequeue(const async_handler& a_on_data, std::chrono::milliseconds a_wait_duration = std::chrono::milliseconds(-1), int repeat_count = 0) { - if (m_is_canceled) return false; - T value; - if (m_queue.pop(value)) - return a_on_data(value, boost::system::error_code()); - else if (a_wait_duration == std::chrono::milliseconds(0)) - return false; + if (m_queue.pop(value)) { + if (!a_on_data(value, boost::system::error_code())) + return true; + if (repeat_count > 0) --repeat_count; + } + + if (a_wait_duration == std::chrono::milliseconds(0) || !repeat_count) + return true; std::chrono::milliseconds timeout = a_wait_duration < std::chrono::milliseconds(0) diff --git a/test/test_async_queue.cpp b/test/test_async_queue.cpp index b974d43..2ba49d1 100644 --- a/test/test_async_queue.cpp +++ b/test/test_async_queue.cpp @@ -52,10 +52,13 @@ BOOST_AUTO_TEST_CASE( test_async_queue ) std::shared_ptr> q(new async_queue(io)); bool res = q->async_dequeue( - [](int& a, const boost::system::error_code& ec) { i = a; return false; }, + [](int& a, const boost::system::error_code& ec) { + throw std::exception(); // This handler is never called + return false; + }, std::chrono::milliseconds(0)); - BOOST_REQUIRE(!res); + BOOST_REQUIRE(res); // Returns true because there was no async dispatch for (i = 10; i < 13; i++) BOOST_REQUIRE(q->enqueue(i)); @@ -86,8 +89,9 @@ BOOST_AUTO_TEST_CASE( test_async_queue ) io.run(); - BOOST_REQUIRE_EQUAL(i, b); - BOOST_REQUIRE_EQUAL(3, n); + BOOST_REQUIRE_EQUAL(3, n); + BOOST_REQUIRE_EQUAL(17, a); + BOOST_REQUIRE_EQUAL(17, b); } namespace { From 369538491d273ab2655c709eadabc9d9db13014f Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 17 Oct 2013 21:25:25 -0400 Subject: [PATCH 012/185] Work in progress --- .gitignore | 1 + configure.ac | 2 +- include/eixx/config.h | 4 +- include/eixx/connect/basic_otp_mailbox.hpp | 202 ++++----------- include/eixx/connect/basic_otp_mailbox.ipp | 207 ++++++++++++++++ .../connect/basic_otp_mailbox_registry.hpp | 168 +------------ .../connect/basic_otp_mailbox_registry.ipp | 232 ++++++++++++++++++ include/eixx/connect/basic_otp_node.hpp | 55 ++--- include/eixx/connect/basic_otp_node.ipp | 173 +++++++++---- .../eixx/connect/detail/basic_rpc_server.hpp | 180 ++++++++++++++ include/eixx/marshal/atom.hpp | 4 +- include/eixx/marshal/eterm_format.ipp | 25 +- include/eixx/marshal/eterm_match.hpp | 48 +++- include/eixx/marshal/pid.hpp | 42 ++-- include/eixx/marshal/pid.ipp | 7 +- include/eixx/marshal/ref.hpp | 88 ++++--- include/eixx/marshal/ref.ipp | 22 +- include/eixx/util/async_queue.hpp | 56 +++-- include/eixx/util/compiler_hints.hpp | 15 +- src/test_node.cpp | 107 ++++---- test/test_async_queue.cpp | 28 ++- test/test_eterm.cpp | 25 +- test/test_eterm_encode.cpp | 2 +- test/test_eterm_match.cpp | 23 +- 24 files changed, 1100 insertions(+), 616 deletions(-) create mode 100644 include/eixx/connect/basic_otp_mailbox.ipp create mode 100644 include/eixx/connect/basic_otp_mailbox_registry.ipp create mode 100644 include/eixx/connect/detail/basic_rpc_server.hpp diff --git a/.gitignore b/.gitignore index 19928a5..55dade6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.swp +*.dump stamp-h1 eixx*.tar.gz aclocal.m4 diff --git a/configure.ac b/configure.ac index cd4a9b4..731dde5 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_ARG_VAR([ERLC_FLAGS], [general flags to prepend to ERLC_FLAGS]) ERLC_FLAGS="${ERLC_FLAGS} +debug_info" # CXXFLAGS="${CXXFLAGS% } -MMD -Wall -fno-strict-aliasing -fpermissive -Wl,-V" -CXXFLAGS="${CXXFLAGS% } -MMD -Wall -fno-strict-aliasing -std=c++11 -DBOOST_SYSTEM_NO_DEPRECATED=1" +CXXFLAGS="${CXXFLAGS% } -MMD -Wall -Wno-unused-local-typedefs -fno-strict-aliasing -std=c++11 -DBOOST_SYSTEM_NO_DEPRECATED=1" AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debug [[default=no]]]), diff --git a/include/eixx/config.h b/include/eixx/config.h index 99b16bb..1de7a2f 100644 --- a/include/eixx/config.h +++ b/include/eixx/config.h @@ -41,7 +41,9 @@ #endif /* Algorithm IDEA in openssl crypto library */ -/* #undef CRYPTO_WITH_IDEA */ +#ifndef EIXX_CRYPTO_WITH_IDEA +#define EIXX_CRYPTO_WITH_IDEA 1 +#endif /* Algorithm MD2 in openssl crypto library */ #ifndef EIXX_CRYPTO_WITH_MD2 diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index 78e2365..9d76af6 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -41,6 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include #include #include #include @@ -52,6 +53,9 @@ template class basic_otp_node; using EIXX_NAMESPACE::marshal::list; using EIXX_NAMESPACE::marshal::epid; +using EIXX_NAMESPACE::marshal::tuple; +using EIXX_NAMESPACE::marshal::varbind; +using namespace std::chrono; /** * Provides a simple mechanism for exchanging messages with Erlang @@ -92,30 +96,39 @@ class basic_otp_mailbox typedef std::shared_ptr > pointer; typedef std::function< - void (basic_otp_mailbox&, - transport_msg*&, - ::boost::system::error_code&) + bool (basic_otp_mailbox&, transport_msg*&) > receive_handler_type; typedef util::async_queue*, Alloc> queue_type; + template friend class basic_otp_node; + template friend class util::async_queue; + template friend class basic_otp_mailbox_registry; + template friend class std::function; + template friend class std::_Function_handler; + private: - boost::asio::io_service& m_io_service; - basic_otp_node& m_node; - epid m_self; - atom m_name; - std::set > m_links; - std::map, epid > m_monitors; - std::shared_ptr m_queue; - std::chrono::time_point< - std::chrono::system_clock> m_time_freed; // Cache time of this mbox - receive_handler_type m_handler; // Called on async_receive + boost::asio::io_service& m_io_service; + basic_otp_node& m_node; + epid m_self; + atom m_name; + std::set > m_links; + std::map, epid > m_monitors; + std::shared_ptr m_queue; + system_clock::time_point m_time_freed; // Cache time of this mbox void do_deliver(transport_msg* a_msg); - bool operator() (transport_msg*& a_msg, const boost::system::error_code& ec); + void name(const atom& a_name) { m_name = a_name; } public: + basic_otp_mailbox( + basic_otp_node& a_node, const epid& a_self, + const atom& a_name = atom(), boost::asio::io_service* a_svc = NULL, + const Alloc& a_alloc = Alloc()) + : basic_otp_mailbox(a_node, a_self, a_name, 255, a_svc, a_alloc) + {} + basic_otp_mailbox( basic_otp_node& a_node, const epid& a_self, const atom& a_name = atom(), int a_queue_size = 255, @@ -124,7 +137,6 @@ class basic_otp_mailbox , m_node(a_node), m_self(a_self) , m_name(a_name) , m_queue(new queue_type(m_io_service, a_queue_size, a_alloc)) - , m_time_freed(std::chrono::microseconds(0)) {} ~basic_otp_mailbox() { @@ -146,11 +158,11 @@ class basic_otp_mailbox /// Indicates if mailbox doesn't have any pending messages bool empty() const { return m_queue.empty(); } - void register(const atom& a_name) { - if (m_node. - m_name = a_name; + /// Time when this mailbox was placed in the free list + system_clock::time_point time_freed() const { return m_time_freed; } - } + /// Register current mailbox under the given name + bool reg(const atom& a_name) { return m_node.register_mailbox(a_name, *this); } bool operator== (const basic_otp_mailbox& rhs) const { return self() == rhs.self(); } bool operator!= (const basic_otp_mailbox& rhs) const { return self() != rhs.self(); } @@ -161,12 +173,14 @@ class basic_otp_mailbox /// Print pid and regname of the mailbox to the given stream std::ostream& dump(std::ostream& out) const; + /* /// Find the first message in the mailbox matching a pattern. /// Return the message, and if \a a_binding is not NULL set the binding variables. /// The call is not thread-safe and should be evaluated in the thread running the /// mailbox node's service. transport_msg* match(const eterm& a_pattern, varbind* a_binding = NULL); + */ /// Dequeue the next message from the mailbox. The call is non-blocking and /// returns NULL if no messages are waiting. @@ -203,10 +217,18 @@ class basic_otp_mailbox * Cancel pending asynchronous receive operation */ void cancel_async_receive() { - m_handler = nullptr; m_queue->cancel(); } + /** + * Wait for messages and perform pattern match when a message arives + */ + bool async_match(const marshal::eterm_pattern_matcher& a_matcher, + const std::function&)>& a_on_timeout, + std::chrono::milliseconds a_timeout = std::chrono::milliseconds(-1), + int a_repeat_count = 0) + throw (std::runtime_error); + /// Deliver a message to this mailbox. The call is thread-safe. void deliver(const transport_msg& a_msg) { transport_msg* p = new transport_msg(a_msg); @@ -316,144 +338,6 @@ class basic_otp_mailbox } }; -//------------------------------------------------------------------------------ -// basic_otp_mailbox implementation -//------------------------------------------------------------------------------ - -template -void basic_otp_mailbox:: -close(const eterm& a_reason = am_normal, bool a_reg_remove = true) { - m_handler = nullptr; - m_queue->reset(); - m_time_freed = std::chrono::system_clock::now(); - if (a_reg_remove) - m_node.close_mailbox(this); - break_links(a_reason); - m_name = atom(); -} - -template -bool basic_otp_mailbox:: -operator() (transport_msg*& a_msg, const boost::system::error_code& ec) -{ - if (m_time_freed != std::chrono::microseconds(0) || !m_handler) - return false; - m_handler(*this, a_msg, ec); - if (a_msg) { - delete a_msg; - a_msg = NULL; - } - return true; -} - -template -bool basic_otp_mailbox:: -async_receive(receive_handler_type h, std::chrono::milliseconds a_timeout, - int a_repeat_count) throw (std::runtime_error) -{ - m_handler = h; - return m_queue->async_dequeue(*this, a_timeout, a_repeat_count); -} - -template -void basic_otp_mailbox:: -break_links(const eterm& a_reason) -{ - for (typename std::set >::const_iterator - it=m_links.begin(), end = m_links.end(); it != end; ++it) - try { m_node.send_exit(self(), *it, a_reason); } catch(...) {} - for (typename std::map, epid >::const_iterator - it = m_monitors.begin(), end = m_monitors.end(); it != end; ++it) - try { m_node.send_monitor_exit(self(), it->second, it->first, a_reason); } catch(...) {} - if (!m_links.empty()) m_links.clear(); - if (!m_monitors.empty()) m_monitors.clear(); -} - -template -transport_msg* basic_otp_mailbox:: -match(const eterm& a_pattern, varbind* a_binding) -{ - for (typename queue_type::iterator it = m_queue.begin(), e = m_queue.end(); - it != e; ++it) - { - transport_msg* p = *it; - BOOST_ASSERT(p); - if (a_pattern.match(p->msg(), a_binding)) { - // Found a match - m_queue.erase(it); - return p; - } - } - return NULL; -} - -template -void basic_otp_mailbox:: -do_deliver(transport_msg* a_msg) -{ - try { - switch (a_msg->type()) { - case transport_msg::LINK: - BOOST_ASSERT(a_msg->recipient_pid() == self()); - m_links.insert(a_msg->sender_pid()); - delete a_msg; - return; - - case transport_msg::UNLINK: - BOOST_ASSERT(a_msg->recipient_pid() == self()); - m_links.erase(a_msg->sender_pid()); - delete a_msg; - return; - - case transport_msg::MONITOR_P: - BOOST_ASSERT((a_msg->recipient().type() == PID && a_msg->recipient_pid() == self()) - || a_msg->recipient().to_atom() == m_name); - m_monitors.insert( - std::pair, epid >(a_msg->get_ref(), a_msg->sender_pid())); - delete a_msg; - return; - - case transport_msg::DEMONITOR_P: - m_monitors.erase(a_msg->get_ref()); - delete a_msg; - return; - - case transport_msg::MONITOR_P_EXIT: - m_monitors.erase(a_msg->get_ref()); - m_queue.push_back(a_msg); - break; - - case transport_msg::EXIT2: - case transport_msg::EXIT2_TT: - BOOST_ASSERT(a_msg->recipient_pid() == self()); - m_links.erase(a_msg->sender_pid()); - m_queue.push_back(a_msg); - break; - - default: - m_queue.push_back(a_msg); - } - } catch (std::exception& e) { - a_msg->set_error_flag(); - m_queue.push_back(a_msg); - } - - // If the timer's expiration is set to some non-default value, it means that - // there's an outstanding asynchronous receive operation. We cancel the timer - // that will cause invocation of the handler passed to the deadline timer - // upon executing mailbox->async_receive(Handler, Timeout). - if (m_deadline_timer.expires_at() != boost::asio::deadline_timer_ex::time_type()) - m_deadline_timer.cancel(); -} - -template -std::ostream& basic_otp_mailbox:: -dump(std::ostream& out) const { - out << "#Mbox{pid=" << self(); - if (m_name != atom()) out << ", name=" << m_name; - return out << '}'; -} - } // namespace connect } // namespace EIXX_NAMESPACE @@ -468,4 +352,6 @@ namespace std { } // namespace std +#include + #endif // _EIXX_BASIC_OTP_MAILBOX_HPP_ diff --git a/include/eixx/connect/basic_otp_mailbox.ipp b/include/eixx/connect/basic_otp_mailbox.ipp new file mode 100644 index 0000000..52bd29f --- /dev/null +++ b/include/eixx/connect/basic_otp_mailbox.ipp @@ -0,0 +1,207 @@ +//---------------------------------------------------------------------------- +/// \file basic_otp_mailbox.ipp +//---------------------------------------------------------------------------- +/// \brief Implemention of basic mailbox functionality. +//---------------------------------------------------------------------------- +// Copyright (c) 2010 Serge Aleynikov +// Created: 2010-09-20 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the eixx (Erlang C++ Interface) library. + +Copyright (c) 2010 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ + +#ifndef _EIXX_BASIC_OTP_MAILBOX_IPP_ +#define _EIXX_BASIC_OTP_MAILBOX_IPP_ + +namespace EIXX_NAMESPACE { +namespace connect { + +//------------------------------------------------------------------------------ +// basic_otp_mailbox implementation +//------------------------------------------------------------------------------ + +template +void basic_otp_mailbox:: +close(const eterm& a_reason, bool a_reg_remove) { + m_time_freed = std::chrono::system_clock::now(); + m_queue->reset(); + if (a_reg_remove) + m_node.close_mailbox(this); + break_links(a_reason); + m_name = atom(); +} + +template +bool basic_otp_mailbox:: +async_receive(receive_handler_type h, std::chrono::milliseconds a_timeout, + int a_repeat_count) throw (std::runtime_error) +{ + return m_queue->async_dequeue( + [this, h](transport_msg*& a_msg, const boost::system::error_code& ec) { + if (this->m_time_freed.time_since_epoch().count() == 0 || !h) + return false; + bool res; + if (ec) { + transport_msg* p(nullptr); + res = h(*this, p); + } else { + res = h(*this, a_msg); + if (a_msg) { + delete a_msg; + a_msg = nullptr; + } + } + + return res; + }, + a_timeout, + a_repeat_count); +} + +template +bool basic_otp_mailbox:: +async_match(const marshal::eterm_pattern_matcher& a_matcher, + const std::function&)>& a_on_timeout, + std::chrono::milliseconds a_timeout, + int a_repeat_count) throw (std::runtime_error) +{ + auto f = + [this, &a_matcher, a_on_timeout] + (transport_msg*& a_msg, const boost::system::error_code& ec) { + if (this->m_time_freed.time_since_epoch().count() == 0) + return false; + bool res; + if (ec) { + a_on_timeout(*this); + return false; + } + varbind binding; + if (a_msg) { + a_matcher.match(a_msg->msg(), &binding); + delete a_msg; + a_msg = nullptr; + } + return true; + }; + + return m_queue->async_dequeue(f, a_timeout, a_repeat_count); +} + +template +void basic_otp_mailbox:: +break_links(const eterm& a_reason) +{ + for (typename std::set >::const_iterator + it=m_links.begin(), end = m_links.end(); it != end; ++it) + try { m_node.send_exit(self(), *it, a_reason); } catch(...) {} + for (typename std::map, epid >::const_iterator + it = m_monitors.begin(), end = m_monitors.end(); it != end; ++it) + try { m_node.send_monitor_exit(self(), it->second, it->first, a_reason); } catch(...) {} + if (!m_links.empty()) m_links.clear(); + if (!m_monitors.empty()) m_monitors.clear(); +} + +/* +template +transport_msg* basic_otp_mailbox:: +match(const eterm& a_pattern, varbind* a_binding) +{ + for (typename queue_type::iterator it = m_queue->begin(), e = m_queue->end(); + it != e; ++it) + { + transport_msg* p = *it; + BOOST_ASSERT(p); + if (a_pattern.match(p->msg(), a_binding)) { + // Found a match + m_queue.erase(it); + return p; + } + } + return NULL; +} +*/ + +template +void basic_otp_mailbox:: +do_deliver(transport_msg* a_msg) +{ + try { + switch (a_msg->type()) { + case transport_msg::LINK: + BOOST_ASSERT(a_msg->recipient_pid() == self()); + m_links.insert(a_msg->sender_pid()); + delete a_msg; + return; + + case transport_msg::UNLINK: + BOOST_ASSERT(a_msg->recipient_pid() == self()); + m_links.erase(a_msg->sender_pid()); + delete a_msg; + return; + + case transport_msg::MONITOR_P: + BOOST_ASSERT((a_msg->recipient().type() == PID && a_msg->recipient_pid() == self()) + || a_msg->recipient().to_atom() == m_name); + m_monitors.insert( + std::pair, epid >(a_msg->get_ref(), a_msg->sender_pid())); + delete a_msg; + return; + + case transport_msg::DEMONITOR_P: + m_monitors.erase(a_msg->get_ref()); + delete a_msg; + return; + + case transport_msg::MONITOR_P_EXIT: + m_monitors.erase(a_msg->get_ref()); + m_queue.push_back(a_msg); + break; + + case transport_msg::EXIT2: + case transport_msg::EXIT2_TT: + BOOST_ASSERT(a_msg->recipient_pid() == self()); + m_links.erase(a_msg->sender_pid()); + m_queue.push_back(a_msg); + break; + + default: + m_queue.push_back(a_msg); + } + } catch (std::exception& e) { + a_msg->set_error_flag(); + m_queue.push_back(a_msg); + } +} + +template +std::ostream& basic_otp_mailbox:: +dump(std::ostream& out) const { + out << "#Mbox{pid=" << self(); + if (m_name != atom()) out << ", name=" << m_name; + return out << '}'; +} + +} // namespace connect +} // namespace EIXX_NAMESPACE + +#endif // _EIXX_BASIC_OTP_MAILBOX_IPP_ diff --git a/include/eixx/connect/basic_otp_mailbox_registry.hpp b/include/eixx/connect/basic_otp_mailbox_registry.hpp index d042905..90abe2c 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.hpp +++ b/include/eixx/connect/basic_otp_mailbox_registry.hpp @@ -45,10 +45,11 @@ namespace connect { using detail::lock_guard; template -class basic_otp_mailbox_registry { +struct basic_otp_mailbox_registry { typedef basic_otp_mailbox mailbox_type; typedef mailbox_type* mailbox_ptr; +private: basic_otp_node& m_owner_node; // These are made mutable so that intrinsic cleanup is possible // of orphant entries. @@ -58,12 +59,12 @@ class basic_otp_mailbox_registry { // Cache of freed mailboxes static std::queue s_free_list; + static Mutex s_free_list_lock; + public: basic_otp_mailbox_registry(basic_otp_node& a_owner) : m_owner_node(a_owner) - { - - } + {} ~basic_otp_mailbox_registry() { clear(); @@ -114,164 +115,9 @@ class basic_otp_mailbox_registry { size_t count() const { return m_by_pid.size(); } }; -//------------------------------------------------------------------------------ -// otp_mailbox_registry implementation -//------------------------------------------------------------------------------ - - -template -typename basic_otp_mailbox_registry::mailbox_ptr -basic_otp_mailbox_registry:: -create_mailbox(const atom& a_name, boost::asio::io_service* a_svc) -{ - lock_guard guard(m_lock); - if (!a_name.empty()) { - typename std::map::iterator it = m_by_name.find(a_name); - if (it != m_by_name.end()) - return it->second; // Already registered! - } - - epid l_pid = m_owner_node.create_pid(); - mailbox_ptr mbox = new mailbox_type(m_owner_node, l_pid, a_name, a_svc); - if (!a_name.empty()) - m_by_name.insert(std::pair(a_name, mbox)); - m_by_pid.insert(std::pair, mailbox_ptr>(l_pid, mbox)); - return mbox; -} - -template -void basic_otp_mailbox_registry:: -clear() -{ - if (!m_by_name.empty() || !m_by_pid.empty()) { - lock_guard guard(m_lock); - m_by_name.clear(); - typename std::map, mailbox_ptr>::iterator it; - for(it = m_by_pid.begin(); it != m_by_pid.end(); ++it) { - mailbox_ptr p = it->second; - p->close(am_normal, false); - } - m_by_pid.clear(); - } -} - -template -bool basic_otp_mailbox_registry:: -add(atom a_name, mailbox_ptr a_mbox) -{ - if (a_name.empty()) - throw err_bad_argument("Empty registering name!"); - if (!a_mbox->name().empty()) - throw err_bad_argument("Mailbox already registered as", a_mbox->name()); - lock_guard guard(m_lock); - auto it = m_by_name.insert(std::pair(a_name, a_mbox)); - if (it.second) - a_mbox->name(a_name); - return it.second; -} - -/// Unregister a name so that no mailbox is any longer associated with \a a_name. -template -bool basic_otp_mailbox_registry:: -erase(atom a_name) -{ - if (!a_name.empty()) - return false; - lock_guard guard(m_lock); - typename std::map::iterator it = m_by_name.find(a_name); - if (it == m_by_name.end()) - return false; - it->second.name(atom()); - m_by_name.erase(it); - return true; -} - -/// Remove \a a_mbox mailbox from the registry -template -void basic_otp_mailbox_registry:: -erase(mailbox_ptr a_mbox) -{ - if (!a_mbox) - return; - lock_guard guard(m_lock); - m_by_pid.erase(a_mbox->self()); - if (!a_mbox->name().empty()) - m_by_name.erase(a_mbox->name()); - a_mbox->name(atom()); -} - -/** - * Look up a mailbox based on its name or pid. - */ -template -typename basic_otp_mailbox_registry::mailbox_ptr -basic_otp_mailbox_registry:: -get(const eterm& a_proc) const throw (err_bad_argument, err_no_process) -{ - switch (a_proc.type()) { - case ATOM: return get(a_proc.to_atom()); - case PID: return get(a_proc.to_pid()); - default: throw err_bad_argument("Unknown process identifier", a_proc); - } -} - -/** - * Look up a mailbox based on its name. If the mailbox has gone out - * of scope we also remove the reference from the hashtable so we - * don't find it again. - */ -template -typename basic_otp_mailbox_registry::mailbox_ptr -basic_otp_mailbox_registry:: -get(atom a_name) const throw(err_no_process) -{ - lock_guard guard(m_lock); - typename std::map::iterator it = m_by_name.find(a_name); - if (it != m_by_name.end()) - return it->second; - throw err_no_process("Process not registered", a_name); -} - -/** - * Look up a mailbox based on its pid. If the mailbox has gone out - * of scope we also remove the reference from the hashtable so we - * don't find it again. - */ -template -typename basic_otp_mailbox_registry::mailbox_ptr -basic_otp_mailbox_registry::get(const epid& a_pid) const - throw(err_no_process) -{ - lock_guard guard(m_lock); - typename std::map, mailbox_ptr>::iterator it = m_by_pid.find(a_pid); - if (it != m_by_pid.end()) - return it->second; - throw err_no_process("Process not found", a_pid); -} - -template -void basic_otp_mailbox_registry::names(std::list& list) -{ - list.clear(); - lock_guard guard(m_lock); - list.resize(m_by_name.size()); - for(typename std::map::const_iterator - it = m_by_name.begin(), end = m_by_name.end(); it != end; ++it) - list.push_back(it->first); -} - -template -void basic_otp_mailbox_registry::pids(std::list >& list) -{ - list.clear(); - lock_guard guard(m_lock); - list.resize(m_by_pid.size()); - for(typename std::map, mailbox_ptr>::const_iterator - it = m_by_pid.begin(), end = m_by_pid.eend(); it != end; ++it) - list.push_back(it->first); -} - } // namespace connect } // namespace EIXX_NAMESPACE +#include + #endif // _EIXX_BASIC_OTP_MAILBOX_REGISTRTY_HPP_ diff --git a/include/eixx/connect/basic_otp_mailbox_registry.ipp b/include/eixx/connect/basic_otp_mailbox_registry.ipp new file mode 100644 index 0000000..40dee1b --- /dev/null +++ b/include/eixx/connect/basic_otp_mailbox_registry.ipp @@ -0,0 +1,232 @@ +//---------------------------------------------------------------------------- +/// \file basic_otp_mailbox_registry.ipp +//---------------------------------------------------------------------------- +/// \brief Implemention details of mailbox registration functionality +//---------------------------------------------------------------------------- +// Copyright (c) 2010 Serge Aleynikov +// Created: 2010-09-20 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the eixx (Erlang C++ Interface) library. + +Copyright (c) 2010 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ + +#ifndef _EIXX_BASIC_OTP_MAILBOX_REGISTRTY_IPP_ +#define _EIXX_BASIC_OTP_MAILBOX_REGISTRTY_IPP_ +#include + +namespace EIXX_NAMESPACE { +namespace connect { + +//----------------------------------------------------------------------------- +// Static members instantiation +//----------------------------------------------------------------------------- +template +std::queue::mailbox_ptr> +basic_otp_mailbox_registry::s_free_list; + +template +Mutex +basic_otp_mailbox_registry::s_free_list_lock; + +//----------------------------------------------------------------------------- +// Member functions implementation +//----------------------------------------------------------------------------- + +template +typename basic_otp_mailbox_registry::mailbox_ptr +basic_otp_mailbox_registry:: +create_mailbox(const atom& a_name, boost::asio::io_service* a_svc) +{ + static const std::chrono::seconds s_min_retention(180); + + lock_guard guard(m_lock); + if (!a_name.empty()) { + typename std::map::iterator it = m_by_name.find(a_name); + if (it != m_by_name.end()) + return it->second; // Already registered! + } + + mailbox_ptr p = nullptr; + + // Mailboxes are cached, so that they can be reused at some later point + // to prevent overflowing the max number of available pid numbers + { + lock_guard g(s_free_list_lock); + if (!s_free_list.empty() && + std::chrono::duration_cast( + std::chrono::system_clock::now() - + s_free_list.back()->time_freed()) > s_min_retention) + { + p = s_free_list.back(); + s_free_list.pop(); + p->name(a_name); + } + } + + if (p == nullptr) { + epid l_pid = m_owner_node.create_pid(); + p = new mailbox_type(m_owner_node, l_pid, a_name, a_svc); + } + + if (!a_name.empty()) + m_by_name.insert(std::pair(a_name, p)); + m_by_pid.insert(std::pair, mailbox_ptr>(p->self(), p)); + return p; +} + +template +void basic_otp_mailbox_registry:: +clear() +{ + if (!m_by_name.empty() || !m_by_pid.empty()) { + lock_guard guard(m_lock); + m_by_name.clear(); + typename std::map, mailbox_ptr>::iterator it; + for(it = m_by_pid.begin(); it != m_by_pid.end(); ++it) { + mailbox_ptr p = it->second; + p->close(am_normal, false); + } + m_by_pid.clear(); + } +} + +template +bool basic_otp_mailbox_registry:: +add(atom a_name, mailbox_ptr a_mbox) +{ + if (a_name.empty()) + throw err_bad_argument("Empty registering name!"); + if (!a_mbox->name().empty()) + throw err_bad_argument("Mailbox already registered as", a_mbox->name()); + lock_guard guard(m_lock); + auto it = m_by_name.insert(std::pair(a_name, a_mbox)); + if (it.second) + a_mbox->name(a_name); + return it.second; +} + +/// Unregister a name so that no mailbox is any longer associated with \a a_name. +template +bool basic_otp_mailbox_registry:: +erase(const atom& a_name) +{ + if (!a_name.empty()) + return false; + lock_guard guard(m_lock); + typename std::map::iterator it = m_by_name.find(a_name); + if (it == m_by_name.end()) + return false; + it->second.name(atom()); + m_by_name.erase(it); + return true; +} + +/// Remove \a a_mbox mailbox from the registry +template +void basic_otp_mailbox_registry:: +erase(mailbox_ptr a_mbox) +{ + if (!a_mbox) + return; + lock_guard guard(m_lock); + m_by_pid.erase(a_mbox->self()); + if (!a_mbox->name().empty()) + m_by_name.erase(a_mbox->name()); + a_mbox->name(atom()); +} + +/** + * Look up a mailbox based on its name or pid. + */ +template +typename basic_otp_mailbox_registry::mailbox_ptr +basic_otp_mailbox_registry:: +get(const eterm& a_proc) const throw (err_bad_argument, err_no_process) +{ + switch (a_proc.type()) { + case ATOM: return get(a_proc.to_atom()); + case PID: return get(a_proc.to_pid()); + default: throw err_bad_argument("Unknown process identifier", a_proc); + } +} + +/** + * Look up a mailbox based on its name. If the mailbox has gone out + * of scope we also remove the reference from the hashtable so we + * don't find it again. + */ +template +typename basic_otp_mailbox_registry::mailbox_ptr +basic_otp_mailbox_registry:: +get(atom a_name) const throw(err_no_process) +{ + lock_guard guard(m_lock); + typename std::map::iterator it = m_by_name.find(a_name); + if (it != m_by_name.end()) + return it->second; + throw err_no_process("Process not registered", a_name); +} + +/** + * Look up a mailbox based on its pid. If the mailbox has gone out + * of scope we also remove the reference from the hashtable so we + * don't find it again. + */ +template +typename basic_otp_mailbox_registry::mailbox_ptr +basic_otp_mailbox_registry::get(const epid& a_pid) const + throw(err_no_process) +{ + lock_guard guard(m_lock); + typename std::map, mailbox_ptr>::iterator it = m_by_pid.find(a_pid); + if (it != m_by_pid.end()) + return it->second; + throw err_no_process("Process not found", a_pid); +} + +template +void basic_otp_mailbox_registry::names(std::list& list) +{ + list.clear(); + lock_guard guard(m_lock); + list.resize(m_by_name.size()); + for(typename std::map::const_iterator + it = m_by_name.begin(), end = m_by_name.end(); it != end; ++it) + list.push_back(it->first); +} + +template +void basic_otp_mailbox_registry::pids(std::list >& list) +{ + list.clear(); + lock_guard guard(m_lock); + list.resize(m_by_pid.size()); + for(typename std::map, mailbox_ptr>::const_iterator + it = m_by_pid.begin(), end = m_by_pid.eend(); it != end; ++it) + list.push_back(it->first); +} + +} // namespace connect +} // namespace EIXX_NAMESPACE + +#endif // _EIXX_BASIC_OTP_MAILBOX_REGISTRTY_IPP_ diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index 221f392..c909e6d 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -82,37 +82,16 @@ class basic_otp_node: public basic_otp_node_local { atom, typename connection_t::pointer, atom_con_hash_fun > conn_hash_map; - class atom_con_hash_fun { - conn_hash_map& map; - - static size_t init_default_hash_size() { - const char* p = getenv("EI_MAX_NODE_CONNECTIONS"); - int n = (p && p[0]) ? atoi(p) : 1024; - if (n < 0 || n >= 64*1024) n = 1024; - return n; - } - public: - static size_t get_default_hash_size() { - static const size_t s_max_node_connections = init_default_hash_size(); - return s_max_node_connections; - } - - atom_con_hash_fun(conn_hash_map* a_map) : map(*a_map) {} + class rpc_server; - size_t operator()(const atom& data) const { - return data.index() % map.bucket_count(); - } - }; - - uint8_t m_creation; - uint32_t m_pid_count; - uint32_t m_port_count; - uint32_t m_serial; - uint32_t m_refid[3]; + uint8_t m_creation; + std::atomic_int m_pid_count; + std::atomic_int m_port_count; + std::atomic_uint_fast64_t m_refid0; + std::atomic_int m_refid1; boost::asio::io_service& m_io_service; Mutex m_lock; - Mutex m_inc_lock; basic_otp_mailbox_registry m_mailboxes; conn_hash_map m_connections; Alloc m_allocator; @@ -128,6 +107,9 @@ class basic_otp_node: public basic_otp_node_local { } void report_status(report_level a_level, const connection_t* a_con, const std::string& s); + void rpc_call(const epid& a_from, const ref& a_ref, + const atom& a_mod, const atom& a_fun, const list& a_args, + const eterm& a_gleader); protected: /// Publish the node port to epmd making this node known to the world. @@ -234,7 +216,8 @@ class basic_otp_node: public basic_otp_node_local { const mailbox_registry_t& registry() const { return m_mailboxes; } - bool register_mailbox(atom a_name) + /// Register mailbox by given name + bool register_mailbox(const atom& a_name, basic_otp_mailbox& a_mbox); /// Create a new unique pid epid create_pid(); @@ -258,8 +241,8 @@ class basic_otp_node: public basic_otp_node_local { * and is not started. */ template - void connect(CompletionHandler h, atom a_remote_node, - atom a_cookie = atom(), size_t a_reconnect_secs = 0) + void connect(CompletionHandler h, const atom& a_remote_node, + const atom& a_cookie = atom(), size_t a_reconnect_secs = 0) throw(err_connection); /** @@ -271,8 +254,8 @@ class basic_otp_node: public basic_otp_node_local { * and is not started. */ template - void connect(CompletionHandler h, atom a_remote_nodename, size_t a_reconnect_secs = 0) - throw(err_connection) + void connect(CompletionHandler h, const atom& a_remote_nodename, + size_t a_reconnect_secs = 0) throw(err_connection) { connect(h, a_remote_nodename, atom(), a_reconnect_secs); } @@ -280,7 +263,7 @@ class basic_otp_node: public basic_otp_node_local { /// Get connection identified by the \a a_node name. /// @throws err_connection if not connected to \a a_node._ connection_t& connection(atom a_nodename) const { - typename conn_hash_map::const_iterator l_con = m_connections.find(a_nodename); + auto l_con = m_connections.find(a_nodename); if (l_con == m_connections.end()) throw err_connection("Not connected to node", a_nodename); return *l_con->second.get(); @@ -303,6 +286,11 @@ class basic_otp_node: public basic_otp_node_local { void (self&, const connection_t*, report_level, const std::string&) > on_status; + boost::function< + eterm (const epid& a_from, const ref& a_ref, + const atom& a_mod, const atom& a_fun, const list& a_args, + const eterm& a_gleader) + > on_rpc_call; /** * Accept connections from client processes. * This method sets the socket listener for incoming connections and @@ -410,5 +398,6 @@ class basic_otp_node: public basic_otp_node_local { } // namespace EIXX_NAMESPACE #include +#include #endif // _EIXX_BASIC_OTP_NODE_HPP_ diff --git a/include/eixx/connect/basic_otp_node.ipp b/include/eixx/connect/basic_otp_node.ipp index a99c78c..bad0f12 100644 --- a/include/eixx/connect/basic_otp_node.ipp +++ b/include/eixx/connect/basic_otp_node.ipp @@ -30,80 +30,133 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***** END LICENSE BLOCK ***** */ +#include #include +#include #include +#include namespace EIXX_NAMESPACE { namespace connect { -////////////////////////////////////////////////////////////////////////// -// enode_local +namespace { + using namespace std::placeholders; + using marshal::var; +} + +//----------------------------------------------------------------------------- +// basic_otp_node::atom_con_hash_fun +//----------------------------------------------------------------------------- +template +class basic_otp_node::atom_con_hash_fun { + conn_hash_map& map; + + static size_t init_default_hash_size() { + const char* p = getenv("EI_MAX_NODE_CONNECTIONS"); + int n = (p && p[0]) ? atoi(p) : 1024; + if (n < 0 || n >= 64*1024) n = 1024; + return n; + } +public: + static size_t get_default_hash_size() { + static const size_t s_max_node_connections = init_default_hash_size(); + return s_max_node_connections; + } + + atom_con_hash_fun(conn_hash_map* a_map) : map(*a_map) {} + + size_t operator()(const atom& data) const { + return data.index() % map.bucket_count(); + } +}; + +//----------------------------------------------------------------------------- +// basic_otp_node +//----------------------------------------------------------------------------- template -basic_otp_node::basic_otp_node( +basic_otp_node:: +basic_otp_node( boost::asio::io_service& a_io_svc, const std::string& a_nodename, const std::string& a_cookie, const Alloc& a_alloc, int8_t a_creation) throw (err_bad_argument, err_connection, eterm_exception) : basic_otp_node_local(a_nodename, a_cookie) - , m_creation((a_creation < 0 ? time(NULL) : (int)a_creation) & 0x03) // Creation counter + , m_creation((a_creation < 0 ? time(NULL) : (int)a_creation) & 0x03) , m_pid_count(1) , m_port_count(1) - , m_serial(0) + , m_refid0(1) + , m_refid1(0) , m_io_service(a_io_svc) , m_mailboxes(*this) , m_connections(atom_con_hash_fun::get_default_hash_size(), atom_con_hash_fun(&m_connections)) , m_allocator(a_alloc) -{ - // Init the counters - m_refid[0] = 1; - m_refid[1] = 0; - m_refid[2] = 0; - m_verboseness = verboseness::level(); -} + , m_verboseness(verboseness::level()) +{} template -epid basic_otp_node::create_pid() { - lock_guard guard(m_inc_lock); - epid p(m_nodename, m_pid_count++, m_serial, m_creation, m_allocator); - if (m_pid_count > 0x7fff) { - m_pid_count = 0; - m_serial = (m_serial + 1) & 0x1fff; /* 13 bits */ +epid basic_otp_node:: +create_pid() +{ + int n; + while (true) { + n = m_pid_count.fetch_add(1, std::memory_order_relaxed); + if (n < 0x0fffffff /* 28 bits */) break; + + if (m_pid_count.exchange(1, std::memory_order_acquire) == 1) { + n = 1; + break; + } } - return p; + + return epid(m_nodename, n, m_creation, m_allocator); } template -port basic_otp_node::create_port() { - lock_guard guard(m_inc_lock); - port p(m_nodename, m_port_count++, m_creation, m_allocator); - - if (m_port_count > 0x0fffffff) /* 28 bits */ - m_port_count = 0; +port basic_otp_node:: +create_port() +{ + int n; + while (true) { + n = m_port_count.fetch_add(1, std::memory_order_relaxed); + if (n < 0x0fffffff /* 28 bits */) break; + + if (m_port_count.exchange(1, std::memory_order_acquire) == 1) { + n = 1; + break; + } + } - return p; + return port(m_nodename, n, m_creation, m_allocator); } template -ref basic_otp_node::create_ref() { - lock_guard guard(m_inc_lock); - ref r(m_nodename, m_refid, m_creation, m_allocator); +ref basic_otp_node:: +create_ref() +{ + uint_fast64_t n; + int mn; + + while (true) { + n = m_refid0.fetch_add(1, std::memory_order_relaxed); + if (n) break; - // increment ref ids (3 ints: 18 + 32 + 32 bits) - if (++m_refid[0] > 0x3ffff) { - m_refid[0] = 0; + int mo = m_refid1.load(std::memory_order_consume); + mn = mo+1; - if (++m_refid[1] == 0) - ++m_refid[2]; + if (mn > 0x3ffff) mn = 0; + + if (m_refid1.compare_exchange_weak(mo, mn, std::memory_order_acquire)) + break; } - return r; + return ref(m_nodename, mn, n, m_creation, m_allocator); } template template -void basic_otp_node::connect( - CompletionHandler h, atom a_remote_node, atom a_cookie, size_t a_reconnect_secs) - throw(err_connection) +void basic_otp_node:: +connect(CompletionHandler h, const atom& a_remote_node, const atom& a_cookie, + size_t a_reconnect_secs) throw(err_connection) { lock_guard guard(m_lock); typename conn_hash_map::iterator it = m_connections.find(a_remote_node); @@ -119,14 +172,31 @@ void basic_otp_node::connect( } } + template -void basic_otp_node::publish_port() throw (err_connection) +void basic_otp_node:: +rpc_call(const epid& a_from, const ref& a_ref, + const atom& a_mod, const atom& a_fun, const list& a_args, + const eterm& a_gleader) +{ + auto res = on_rpc_call + ? on_rpc_call(a_from, a_ref, a_mod, a_fun, a_args, a_gleader) + : eterm( + tuple::make(a_ref, + tuple::make(am_error, am_unsupported))); + send(a_from, res); +} + +template +void basic_otp_node:: +publish_port() throw (err_connection) { throw err_connection("Not implemented!"); } template -void basic_otp_node::unpublish_port() throw (err_connection) +void basic_otp_node:: +unpublish_port() throw (err_connection) { throw std::runtime_error("Not implemented"); } @@ -155,7 +225,8 @@ report_status(report_level a_level, const connection_t* a_con, const std::string } template -void basic_otp_node::deliver(const transport_msg& a_msg) +void basic_otp_node:: +deliver(const transport_msg& a_msg) throw (err_bad_argument, err_no_process, err_connection) { try { @@ -172,8 +243,8 @@ void basic_otp_node::deliver(const transport_msg& a_msg) template template -void basic_otp_node::send( - const atom& a_to_node, ToProc a_to, const transport_msg& a_msg) +void basic_otp_node:: +send(const atom& a_to_node, ToProc a_to, const transport_msg& a_msg) throw (err_no_process, err_connection) { if (a_to_node == nodename()) { @@ -188,8 +259,8 @@ void basic_otp_node::send( } template -void inline basic_otp_node::send( - const epid& a_to, const eterm& a_msg) +void inline basic_otp_node:: +send(const epid& a_to, const eterm& a_msg) throw (err_no_process, err_connection) { transport_msg tm; @@ -198,8 +269,8 @@ void inline basic_otp_node::send( } template -void inline basic_otp_node::send( - const atom& a_node, const epid& a_to, const eterm& a_msg) +void inline basic_otp_node:: +send(const atom& a_node, const epid& a_to, const eterm& a_msg) throw (err_no_process, err_connection) { transport_msg tm; @@ -208,8 +279,8 @@ void inline basic_otp_node::send( } template -void inline basic_otp_node::send( - const epid& a_from, const atom& a_to, const eterm& a_msg) +void inline basic_otp_node:: +send(const epid& a_from, const atom& a_to, const eterm& a_msg) throw (err_no_process, err_connection) { transport_msg tm; @@ -218,8 +289,8 @@ void inline basic_otp_node::send( } template -void inline basic_otp_node::send( - const epid& a_from, const atom& a_to_node, const atom& a_to, const eterm& a_msg) +void inline basic_otp_node:: +send(const epid& a_from, const atom& a_to_node, const atom& a_to, const eterm& a_msg) throw (err_no_process, err_connection) { transport_msg tm; diff --git a/include/eixx/connect/detail/basic_rpc_server.hpp b/include/eixx/connect/detail/basic_rpc_server.hpp new file mode 100644 index 0000000..2566b17 --- /dev/null +++ b/include/eixx/connect/detail/basic_rpc_server.hpp @@ -0,0 +1,180 @@ +//---------------------------------------------------------------------------- +/// \file basic_rpc_server.hpp +//---------------------------------------------------------------------------- +/// \brief A class implementing RPC protocol support for an Erlang node +//---------------------------------------------------------------------------- +// Copyright (c) 2013 Serge Aleynikov +// Created: 2013-10-21 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +This file is part of the eixx (Erlang C++ Interface) library. + +Copyright (c) 2013 Serge Aleynikov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +***** END LICENSE BLOCK ***** +*/ + +#ifndef _EIXX_BASIC_RPC_SERVER_HPP_ +#define _EIXX_BASIC_RPC_SERVER_HPP_ + +#include +#include +#include +#include + +namespace EIXX_NAMESPACE { +namespace connect { + +using marshal::atom; + +/** + * Implements Erlang RPC protocol + */ +template +class basic_otp_node::rpc_server : private Alloc +{ + static const var A; + static const var F; + static const var G; + static const var M; + static const var P; + static const var R; + static const var T; + + basic_otp_node& m_node; + bool m_active; + std::unique_ptr> m_self; + + void rpc_call(const epid& a_from, const ref& a_ref, + const atom& a_mod, const atom& a_fun, const list& a_list, + const eterm& a_gleader) + { + if (m_node.on_rpc_call) + m_node.on_rpc_call(a_from, a_ref, a_mod, a_fun, a_list, a_gleader); + } + +public: + rpc_server(basic_otp_node& a_owner, const Alloc& a_alloc = Alloc()) + : Alloc(a_alloc) + , m_node(a_owner) + , m_active(true) + , m_self(a_owner.create_mailbox(am_rex)) + {} + + ~rpc_server() { + close(); + } + + void close() { + m_active = false; + m_self.reset(); + } + + /// Encode a tuple containing RPC call details + static tuple encode_rpc(const epid& a_from, + const atom& a_mod, const atom& a_fun, + const list& a_args, + const eterm& a_gleader) + { + // {Self, {call, Mod, Fun, Args, GroupLeader}} + return tuple::make(a_from, + tuple::make(am_call, a_mod, a_fun, a_args, a_gleader)); + } + + /// Encode a tuple containing RPC cast details + static tuple encode_rpc_cast(const epid& a_from, + const atom& a_mod, const atom& a_fun, + const list& a_args, + const eterm& a_gleader) + { + // {'$gen_cast', { cast, Mod, Fun, Args, GroupLeader}} + return tuple::make(am_gen_cast, + tuple::make(am_cast, a_mod, a_fun, a_args, a_gleader)); + } + + static eterm decode_rpc(const eterm& a_msg) { + static const eterm s_pattern = eterm::format("{rex, ~v}", var(T)); + + if (a_msg.type() != TUPLE) + return eterm(); + varbind binding; + return a_msg.match(s_pattern, &binding) ? binding[T] : eterm(); + } + + bool operator() (const eterm& a_pat, + const varbind& a_binding, + long a_opaque) + { + // TODO: What do we do on the incoming RPC call? Need to define + // afacility to add RPC callable functions + return false; + } + + void start() { + static const marshal::eterm_pattern_matcher& s_matcher = + { + marshal::eterm_pattern_action( + this->get_allocator(), + std::bind(&basic_otp_node::rpc_call, &m_node, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), + 0, + "{'$gen_call', {~w, ~w}, {call, ~w, ~w, ~w, ~w}}", + P, R, M, F, A, G), + + marshal::eterm_pattern_action( + this->get_allocator(), + std::bind(&basic_otp_node::rpc_call, &m_node, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), + 1, + "{'$gen_cast', {cast, ~w, ~w, ~w, ~w}}", + M, F, A, G), + + marshal::eterm_pattern_action( + this->get_allocator(), + std::bind(&basic_otp_node::rpc_call, &m_node, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), + 2, + "{_, {~w, ~w}, _Cmd}}", + P, R) + }; + + m_self->async_match(s_matcher, *this, std::chrono::milliseconds(-1), -1); + } +}; + +template +const var basic_otp_node::rpc_server::A = var("A", LIST); +template +const var basic_otp_node::rpc_server::F = var("F", ATOM); +template +const var basic_otp_node::rpc_server::G = var("G"); +template +const var basic_otp_node::rpc_server::M = var("M", ATOM); +template +const var basic_otp_node::rpc_server::P = var("P", PID); +template +const var basic_otp_node::rpc_server::R = var("R", REF); +template +const var basic_otp_node::rpc_server::T = var("T"); + + +} // namespace connect +} // namespace EIXX_NAMESPACE + +#endif // _EIXX_BASIC_RPC_SERVER_HPP_ diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index e3add7e..3496562 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -71,9 +71,9 @@ class atom { int m_index; +public: typedef util::atom_table<>::string_t string_t; -public: static util::atom_table<>& atom_table(); /// Returns empty atom @@ -114,7 +114,7 @@ class atom /// Copy atom from another atom. This is a constant time /// SMP safe operation. - atom(atom s) throw() : m_index(s.m_index) {} + atom(const atom& s) throw() : m_index(s.m_index) {} /// Decode an atom from a binary buffer encoded in /// Erlang external binary format. diff --git a/include/eixx/marshal/eterm_format.ipp b/include/eixx/marshal/eterm_format.ipp index 3ca690d..0f495ee 100644 --- a/include/eixx/marshal/eterm_format.ipp +++ b/include/eixx/marshal/eterm_format.ipp @@ -231,17 +231,21 @@ namespace marshal { } /* pstring */ - /// @todo Implement support for parsing tail list expressions in the form - /// "[H | T]". Currently the pipe notation doesn't work. - /* + /** + * Convert a string with variables into an Erlang term. + * * The format letters are: - * a - An atom - * s - A string - * i - An integer - * l - A long integer - * u - An unsigned long integer - * f - A double float - * w - A pointer to some arbitrary term + * @li a - An atom + * @li s - A string + * @li i - An integer + * @li l - A long integer + * @li u - An unsigned long integer + * @li f - A double float + * @li w - A pointer to some arbitrary term + * @li v - A pointer to an Erlang variable + * + * @todo Implement support for parsing tail list expressions in the form + * "[H | T]". Currently the pipe notation doesn't work. */ template static eterm pformat(const char** fmt, va_list* pap, Alloc& a_alloc) @@ -249,6 +253,7 @@ namespace marshal { skip_ws_and_comments(fmt); switch (*(*fmt)++) { + case 'v': return *va_arg(*pap, var*); case 'w': return *va_arg(*pap, eterm*); case 'a': return atom(va_arg(*pap, char*)); case 's': return string(va_arg(*pap, char*), a_alloc); diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index 995c3df..61b373b 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -40,6 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include namespace EIXX_NAMESPACE { namespace marshal { @@ -57,6 +58,7 @@ class eterm_pattern_action; template class eterm_pattern_matcher { std::list, Alloc> m_pattern_list; + std::list< eterm_pattern_action< Alloc >, Alloc > it; public: typedef std::list, Alloc> list_t; typedef typename list_t::const_iterator const_iterator; @@ -96,13 +98,20 @@ class eterm_pattern_matcher { template eterm_pattern_matcher( const struct init_struct (&a_patterns)[N], pattern_functor_t a_fun, - const Alloc& a_alloc = Alloc() - ) + const Alloc& a_alloc = Alloc()) : m_pattern_list(a_alloc) { init(a_patterns, N, a_fun); } + eterm_pattern_matcher( + std::initializer_list> a_list, + const Alloc& a_alloc = Alloc()) + : m_pattern_list(a_alloc) + { + std::copy(a_list.begin(), a_list.end(), m_pattern_list.begin()); + } + /** * Initialize the pattern list from a given array of patterns. */ @@ -179,8 +188,8 @@ class eterm_pattern_matcher { * to every pattern. * @return true if any one pattern matched the term. */ - bool match(const eterm& a_term, - varbind* a_binding = NULL) const + bool match(const eterm& a_term, + varbind* a_binding = NULL) const { bool res = false; for(auto it = m_pattern_list.begin(), end = m_pattern_list.end(); it != end; ++it) { @@ -202,9 +211,9 @@ class eterm_pattern_action { typedef typename eterm_pattern_matcher::pattern_functor_t pattern_functor_t; - eterm m_pattern; - pattern_functor_t m_fun; - long m_opaque; + eterm m_pattern; + pattern_functor_t m_fun; + long m_opaque; public: /** * Create a new pattern match functor. @@ -220,6 +229,31 @@ class eterm_pattern_action { BOOST_ASSERT(m_fun != NULL); } + eterm_pattern_action( + const Alloc& a_alloc, pattern_functor_t& a_fun, long a_opaque, + const char* a_pat_fmt, ...) + : m_fun(a_fun), m_opaque(a_opaque) + { + BOOST_ASSERT(m_fun != NULL); + va_list ap; + va_start(ap, a_pat_fmt); + try { m_pattern = eterm::format(a_alloc, &a_pat_fmt, &ap); } + catch (...) { va_end(ap); throw; } + va_end(ap); + } + + eterm_pattern_action(const eterm_pattern_action& a_rhs) + : m_pattern(a_rhs.m_pattern) + , m_fun(a_rhs.m_fun) + , m_opaque(a_rhs.m_opaque) + {} + + eterm_pattern_action(eterm_pattern_action&& a_rhs) + : m_pattern(std::move(a_rhs.m_pattern)) + , m_fun(std::move(a_rhs.m_fun)) + , m_opaque(a_rhs.m_opaque) + {} + bool operator() (const eterm& a_term, varbind* a_binding) const throw (eterm_exception) diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index f7cb615..baf8d57 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define _IMPL_PID_HPP_ #include +#include #include #include @@ -53,22 +54,26 @@ class epid { // distinguishing pid values between successive node restarts. union u { struct s { - uint8_t creation: 3; - uint16_t serial : 13; uint16_t id : 15; - } s; + uint16_t serial : 13; + uint8_t creation: 2; + } __attribute__((__packed__)) s; uint32_t i; BOOST_STATIC_ASSERT(sizeof(s) == 4); + u(int a_id, uint8_t a_cre) { + i = (a_id & 0x0FFFffff) | ((a_cre & 0x3) << 28); + } + u(uint16_t a_id, uint16_t a_ser, uint8_t a_cre) { s.id = a_id & 0x7fff; s.serial = a_ser & 0x1fff; s.creation = a_cre & 0x03; } } u; atom node; - pid_blob(const atom& a_node, uint16_t a_id, uint16_t a_ser, uint8_t a_cre) - : u(a_id, a_ser, a_cre), node(a_node) + pid_blob(const atom& a_node, int a_id, int8_t a_cre) + : u(a_id, a_cre), node(a_node) {} }; @@ -88,11 +93,11 @@ class epid { } // Must only be called from constructor! - void init(const atom& node, uint16_t id, uint16_t serial, uint8_t creation, - const Alloc& alloc) throw(err_bad_argument) + void init(const atom& node, int id, uint8_t creation, const Alloc& alloc) + throw(err_bad_argument) { m_blob = new blob(1, alloc); - new (m_blob->data()) pid_blob(node, id, serial, creation); + new (m_blob->data()) pid_blob(node, id, creation); #ifdef EIXX_DEBUG std::cerr << "Initialized pid " << *this << " [addr=" << this << ", blob=" << m_blob << ']' << std::endl; @@ -121,19 +126,20 @@ class epid { * @throw err_bad_argument if node is empty or greater than MAX_NODE_LENGTH **/ epid(const char* node, int id, int serial, int creation, const Alloc& a_alloc = Alloc()) - throw(err_bad_argument) - { - int len = strlen(node); - detail::check_node_length(len); - atom l_node(node, len); - init(l_node, id, serial, creation, a_alloc); - } + throw(err_bad_argument) + : epid(atom(node), id, serial, creation, a_alloc) + {} epid(const atom& node, int id, int serial, int creation, const Alloc& a_alloc = Alloc()) - throw(err_bad_argument) + throw(err_bad_argument) + : epid(node, (id & 0x7fff) | ((serial & 0x1fff) << 15), creation, a_alloc) + {} + + epid(const atom& node, int id, int creation, const Alloc& a_alloc = Alloc()) + throw(err_bad_argument) { detail::check_node_length(node.size()); - init(node, id, serial, creation, a_alloc); + init(node, id, creation, a_alloc); } /// Decode the pid from a binary buffer. @@ -199,7 +205,7 @@ class epid { **/ int creation() const { return m_blob ? m_blob->data()->u.s.creation : 0; } - uint32_t id_internal() const { return m_blob ? m_blob->data()->u.i & 0x7FFFFFFF : 0; } + uint32_t id_internal() const { return m_blob ? m_blob->data()->u.i & 0x3FFFffff : 0; } bool operator== (const epid& rhs) const { return id_internal() == rhs.id_internal() && node() == rhs.node(); diff --git a/include/eixx/marshal/pid.ipp b/include/eixx/marshal/pid.ipp index c621631..70c287c 100644 --- a/include/eixx/marshal/pid.ipp +++ b/include/eixx/marshal/pid.ipp @@ -51,11 +51,12 @@ void epid::decode(const char *buf, int& idx, size_t size, const Alloc& al atom l_node(s, len); s += len; - int l_id = get32be(s); - int l_serial = get32be(s); + uint64_t i1 = get32be(s); + uint64_t i2 = get32be(s); + uint64_t l_id = i1 | i2 << 15; int l_creation = get8(s); - init(l_node, l_id, l_serial, l_creation, alloc); + init(l_node, l_id, l_creation, alloc); idx += s - s0; BOOST_ASSERT((size_t)idx <= size); diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index c8e6ef0..f98c830 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -35,6 +35,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define _IMPL_REF_HPP_ #include +#include +#include +#include #include namespace EIXX_NAMESPACE { @@ -52,27 +55,33 @@ class ref { enum { COUNT = 3 }; struct ref_blob { - uint8_t creation; - atom node; - uint32_t ids[COUNT]; - - ref_blob(const atom& a_node, uint32_t* a_ids, uint8_t a_cre) - : creation(a_cre), node(a_node) + atom node; + union { + uint32_t ids[COUNT+1]; + struct { + uint32_t id0; + uint64_t id1; + uint32_t creation; + } __attribute__((__packed__)) s; + } u; + + ref_blob(const atom& a_node, uint32_t a_id0, uint64_t a_id1, uint8_t a_cre) + : node(a_node) { - ids[0] = a_ids[0] & 0x3ffff; - ids[1] = a_ids[1]; - ids[2] = a_ids[2]; + u.s.id0 = a_id0 & 0x3ffff; + u.s.id1 = a_id1; + u.s.creation = a_cre & 0x3; } }; blob* m_blob; // Must only be called from constructor! - void init(const atom& node, uint32_t* ids, int creation, - const Alloc& alloc) throw(err_bad_argument) + void init(const atom& a_node, uint32_t a_id0, uint64_t a_id1, uint8_t a_cre, + const Alloc& alloc) throw(err_bad_argument) { m_blob = new blob(1, alloc); - new (m_blob->data()) ref_blob(node, ids, creation); + new (m_blob->data()) ref_blob(a_node, a_id0, a_id1, a_cre); } void release() { @@ -80,6 +89,9 @@ class ref { m_blob->release(); } + uint32_t id0() const { return m_blob->data()->u.s.id0; } + uint64_t id1() const { return m_blob->data()->u.s.id1; } + public: static const ref null; @@ -97,30 +109,30 @@ class ref { * @throw err_bad_argument if node is empty or greater than MAX_NODE_LENGTH */ template - ref(const char* node, uint32_t (&ids)[N], unsigned int creation, + ref(const char* node, uint32_t (&ids)[N], unsigned int creation, const Alloc& a_alloc = Alloc()) throw(err_bad_argument) - { - BOOST_STATIC_ASSERT(N == 3); - int len = strlen(node); - detail::check_node_length(len); - atom l_node(node, len); - init(l_node, ids, creation, a_alloc); - } + : ref(atom(node), ids[0], ids[1], ids[2], creation, a_alloc) + {} template - ref(const atom& node, uint32_t (&ids)[N], unsigned int creation, + ref(const atom& node, uint32_t (&ids)[N], unsigned int creation, const Alloc& a_alloc = Alloc()) throw(err_bad_argument) + : ref(node, ids[0], ids[1], ids[2], creation, a_alloc) { - detail::check_node_length(node.size()); - init(node, ids, creation, a_alloc); + BOOST_STATIC_ASSERT(N == 3); } - ref(const atom& node, uint32_t id1, uint32_t id2, uint32_t id3, unsigned int creation, + ref(const atom& node, uint32_t id0, uint32_t id1, uint32_t id2, unsigned int creation, + const Alloc& a_alloc = Alloc()) throw(err_bad_argument) + : ref(node, id0, id1 | ((uint64_t)id2 << 32), creation, a_alloc) + {} + + // For internal use + ref(const atom& node, uint32_t id0, uint64_t id1, uint8_t creation, const Alloc& a_alloc = Alloc()) throw(err_bad_argument) { detail::check_node_length(node.size()); - uint32_t ids[] = { id1, id2, id3 }; - init(node, ids, creation, a_alloc); + init(node, id0, id1, creation, a_alloc); } /** @@ -174,31 +186,29 @@ class ref { * Get the id array from the REF. * @return the id array number from the REF. */ - const uint32_t* ids() const { return m_blob ? m_blob->data()->ids : detail::s_ref_ids; } + const uint32_t* ids() const { return m_blob ? m_blob->data()->u.ids : detail::s_ref_ids; } /** * Get the creation number from the REF. * @return the creation number from the REF. */ - int creation() const { return m_blob ? m_blob->data()->creation : 0; } + int creation() const { return m_blob ? m_blob->data()->u.s.creation : 0; } bool operator==(const ref& t) const { return node() == t.node() && - ::memcmp(ids(), t.ids(), COUNT*sizeof(uint32_t)) == 0 && - creation() == t.creation(); + ::memcmp(&m_blob->data()->u, &t.m_blob->data()->u, sizeof(ref_blob::u)) == 0; } /// Less operator, needed for maps bool operator<(const ref& rhs) const { + if (!rhs.m_blob) return m_blob; + if (!m_blob) return true; int n = node().compare(rhs.node()); - if (n < 0) return true; - if (n > 0) return false; - if (id(0) < rhs.id(0)) return true; - if (id(0) > rhs.id(0)) return false; - if (id(1) < rhs.id(1)) return true; - if (id(1) > rhs.id(1)) return false; - if (id(2) < rhs.id(2)) return true; - if (id(2) > rhs.id(2)) return false; + if (n != 0) return n < 0; + if (id0() > rhs.id0()) return true; + if (id0() > rhs.id0()) return false; + if (id1() < rhs.id1()) return true; + if (id1() > rhs.id1()) return false; return false; } @@ -223,7 +233,7 @@ namespace std { template ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::ref& a) { return out << "#Ref<" << a.node() << '.' - << a.id(2) << '.' << a.id(1) << '.' << a.id(0) << '>'; + << a.id(0) << '.' << a.id(1) << '.' << a.id(2) << '>'; } } // namespace std diff --git a/include/eixx/marshal/ref.ipp b/include/eixx/marshal/ref.ipp index 45f0592..5c21cf6 100644 --- a/include/eixx/marshal/ref.ipp +++ b/include/eixx/marshal/ref.ipp @@ -60,12 +60,10 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) s += len; uint8_t l_creation = get8(s) & 0x03; - uint32_t l_ids[COUNT]; + uint32_t l_id0 = get32be(s); + uint64_t l_id1 = get32be(s) | ((uint64_t)get32be(s) << 32); - for (size_t i = 0; i < COUNT; i++) - l_ids[i] = get32be(s); - - init(l_node, l_ids, l_creation, a_alloc); + init(l_node, l_id0, l_id1, l_creation, a_alloc); idx += s-s0; break; @@ -92,9 +90,17 @@ void ref::encode(char* buf, int& idx, size_t size) const s += n; /* now the integers */ - put8(s, (creation() & 0x03)); /* 2 bits */ - for (size_t i=0; i < COUNT; ++i) - put32be(s, ids()[i]); + if (m_blob) { + put8(s, m_blob->data()->u.s.creation); /* 2 bits */ + put32be(s, id0()); + put32be(s, id1() & 0xFFFF); + put32be(s, (id1() >> 32) & 0xFFFF); + } else { + put8(s, 0); /* 2 bits */ + put32be(s, 0u); + put32be(s, 0u); + put32be(s, 0u); + } idx += s-s0; BOOST_ASSERT((size_t)idx <= size); diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index 54e6556..3323db1 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -57,8 +57,10 @@ template> struct async_queue : std::enable_shared_from_this> { typedef boost::lockfree::queue< - T, boost::lockfree::allocator, - boost::lockfree::capacity<256> + T + , boost::lockfree::allocator + , boost::lockfree::capacity<1023> + , boost::lockfree::fixed_sized > queue_type; typedef std::function< @@ -85,18 +87,17 @@ struct async_queue : std::enable_shared_from_this> int i = 0; // Number of handler invocations - bool canceled = ec; - T value; while (i < m_batch_size && m_queue.pop(value)) { i++; repeat_count = dec_repeat_count(repeat_count); - if (!h(value, boost::system::error_code())) { - canceled = true; - break; - } + if (!h(value, boost::system::error_code())) + return; } + static const auto s_timeout = + boost::system::errc::make_error_code(boost::system::errc::timed_out); + // If we reached the batch size and queue has more data // to process - give up the time slice and reschedule the handler if (i == m_batch_size && !m_queue.empty()) { @@ -104,18 +105,18 @@ struct async_queue : std::enable_shared_from_this> (*this->shared_from_this())( h, boost::asio::error::operation_aborted, repeat, repeat_count); }); - } else if (!i && canceled) { + return; + } else if (!i && !h(value, s_timeout)) { // If we haven't processed any data and the timer was canceled. // Invoke the callback to see if we need to remove the handler. - T dummy; - if (!h(dummy, ec)) - return; + return; } int n = dec_repeat_count(repeat_count); // If requested repeated timer, schedule new timer invocation if (repeat > std::chrono::milliseconds(0) && n > 0) { + m_timer.cancel(); m_timer.expires_from_now(repeat); m_timer.async_wait( [this, h, repeat, n] @@ -196,25 +197,32 @@ struct async_queue : std::enable_shared_from_this> if (repeat_count > 0) --repeat_count; } - if (a_wait_duration == std::chrono::milliseconds(0) || !repeat_count) + if (!repeat_count) return true; + auto rep = repeat_count < 0 ? std::numeric_limits::max() : repeat_count; + std::chrono::milliseconds timeout = a_wait_duration < std::chrono::milliseconds(0) ? std::chrono::milliseconds::max() : a_wait_duration; - auto rep = repeat_count < 0 ? std::numeric_limits::max() : repeat_count; - auto repeat_msec = rep > 0 ? timeout : std::chrono::milliseconds(0); - boost::system::error_code ec; - m_timer.cancel(ec); - m_timer.expires_from_now(timeout); - m_timer.async_wait( - [this, &a_on_data, repeat_msec, rep] - (const boost::system::error_code& e) { - (*this->shared_from_this())(a_on_data, e, repeat_msec, rep); - } - ); + if (timeout == std::chrono::milliseconds(0)) + m_io.post([this, &a_on_data, timeout, rep]() { + (*this->shared_from_this())( + a_on_data, boost::system::error_code(), timeout, rep); + }); + else { + boost::system::error_code ec; + m_timer.cancel(ec); + m_timer.expires_from_now(timeout); + m_timer.async_wait( + [this, &a_on_data, timeout, rep] + (const boost::system::error_code& e) { + (*this->shared_from_this())(a_on_data, e, timeout, rep); + } + ); + } return false; } diff --git a/include/eixx/util/compiler_hints.hpp b/include/eixx/util/compiler_hints.hpp index df4b883..07f694a 100644 --- a/include/eixx/util/compiler_hints.hpp +++ b/include/eixx/util/compiler_hints.hpp @@ -12,14 +12,21 @@ #ifndef _EIXX_COMPILER_HINTS_HPP_ #define _EIXX_COMPILER_HINTS_HPP_ +#include + // Branch prediction optimization (see http://lwn.net/Articles/255364/) +namespace EIXX_NAMESPACE { + #ifndef NO_HINT_BRANCH_PREDICTION -# define unlikely(expr) __builtin_expect(!!(expr), 0) -# define likely(expr) __builtin_expect(!!(expr), 1) + inline bool likely(bool expr) { return boost::lockfree::detail::likely (expr); } + inline bool unlikely(bool expr) { return boost::lockfree::detail::unlikely(expr); } #else -# define unlikely(expr) (expr) -# define likely(expr) (expr) + inline bool likely(bool expr) { return expr; } + inline bool unlikely(bool expr) { return expr; } #endif + +} // namespace EIXX_NAMESPACE + #endif // _EIXX_COMPILER_HINTS_HPP_ diff --git a/src/test_node.cpp b/src/test_node.cpp index cff1b07..f61c6e1 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -33,69 +33,44 @@ static const atom N1 = atom("N1"); static const atom N2 = atom("N2"); static const atom N3 = atom("N3"); -void on_io_request(otp_mailbox& a_mbox, boost::system::error_code& ec) { - if (ec == boost::asio::error::operation_aborted) { - eixx::transport_msg* p; - while ((p = a_mbox.receive()) != NULL) { - std::unique_ptr l_tmsg(p); - - static eterm s_put_chars = eterm::format("{io_request,_,_,{put_chars,S}}"); - - varbind l_binding; - if (s_put_chars.match(l_tmsg->msg(), &l_binding)) - std::cerr << "I/O request from server: " - << l_binding[S]->to_string() << std::endl; - else - std::cerr << "I/O server got a message: " << l_tmsg->msg() << std::endl; - } - } else if (ec != boost::asio::error::timeout) - return; - - a_mbox.async_receive(&on_io_request); +bool on_io_request(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) { + + static const eterm s_put_chars = eterm::format("{io_request,_,_,{put_chars,S}}"); + + varbind l_binding; + if (s_put_chars.match(a_msg->msg(), &l_binding)) + std::cerr << "I/O request from server: " + << l_binding[S]->to_string() << std::endl; + else + std::cerr << "I/O server got a message: " << a_msg->msg() << std::endl; + + return true; } -void on_main_msg(otp_mailbox& a_mbox, boost::system::error_code& ec) { - if (ec == boost::asio::error::operation_aborted) { - eixx::transport_msg* p; - while ((p = a_mbox.receive()) != NULL) { - std::unique_ptr l_tmsg(p); - - const eterm& l_msg = l_tmsg->msg(); - - static const eterm s_now_pattern = eterm::format("{rex, {N1, N2, N3}}"); - static const eterm s_stop = atom("stop"); - - varbind l_binding; - - if (s_now_pattern.match(l_msg, &l_binding)) { - struct timeval tv = - { l_binding[N1]->to_long() * 1000000 + - l_binding[N2]->to_long(), - l_binding[N3]->to_long() }; - struct tm tm; - localtime_r(&tv.tv_sec, &tm); - printf("Server time: %02d:%02d:%02d.%06ld\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); - } else if (s_stop.match(l_msg)) { - a_mbox.node().stop(); - return; - } else - std::cout << "Unhandled message: " << l_msg << std::endl; - } - } else if (ec == boost::asio::error::timeout) { - // Make sure that remote node has a process registered as "test". - // Try sending a message to it. - static uint32_t n; - if (n++ & 1) - g_main->send_rpc(g_rem_node, "erlang", "now", list::make()); - else - g_io_server->send_rpc_cast(g_rem_node, atom("io"), atom("put_chars"), - list::make("This is a test string"), &g_io_server->self()); - } else if (ec) { - return; - } - - a_mbox.async_receive(&on_main_msg, 5000); +bool on_main_msg(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) { + static const eterm s_now_pattern = eterm::format("{rex, {N1, N2, N3}}"); + static const eterm s_stop = atom("stop"); + + varbind l_binding; + + const eterm& l_msg = a_msg->msg(); + + if (l_msg.match(s_now_pattern, &l_binding)) { + struct timeval tv = + { l_binding[N1]->to_long() * 1000000 + + l_binding[N2]->to_long(), + l_binding[N3]->to_long() }; + struct tm tm; + localtime_r(&tv.tv_sec, &tm); + printf("Server time: %02d:%02d:%02d.%06ld\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); + } else if (l_msg.match(s_stop)) { + a_mbox.node().stop(); + return false; + } else + std::cout << "Unhandled message: " << l_msg << std::endl; + + return true; } void on_connect(otp_connection* a_con, const std::string& a_error) { @@ -125,7 +100,7 @@ void on_disconnect( int main(int argc, char* argv[]) { if (argc < 2) usage(argv[0]); - + const char* l_nodename = NULL, *l_remote = NULL, *use_cookie = ""; connect::verbose_type verbose = connect::verboseness::level(); int reconnect_secs = 0; @@ -143,7 +118,7 @@ int main(int argc, char* argv[]) { reconnect_secs = atoi(argv[++i]); else usage(argv[0]); - } + } if (!l_nodename || !l_remote) usage(argv[0]); @@ -161,13 +136,13 @@ int main(int argc, char* argv[]) { l_node.connect(&on_connect, g_rem_node, reconnect_secs); //otp_connection::connection_type* l_transport = a_con->transport(); - g_io_server->async_receive(&on_io_request); + g_io_server->async_receive(&on_io_request, std::chrono::milliseconds(-1), -1); //l_node->send_rpc(self, a_con->remote_node(), atom("shell_default"), atom("ls"), // list::make(), &io_server); - g_main->async_receive(&on_main_msg, 5000); + g_main->async_receive(&on_main_msg, std::chrono::seconds(5), -1); l_node.run(); - + return 0; } diff --git a/test/test_async_queue.cpp b/test/test_async_queue.cpp index 2ba49d1..9600a16 100644 --- a/test/test_async_queue.cpp +++ b/test/test_async_queue.cpp @@ -90,12 +90,12 @@ BOOST_AUTO_TEST_CASE( test_async_queue ) io.run(); BOOST_REQUIRE_EQUAL(3, n); - BOOST_REQUIRE_EQUAL(17, a); - BOOST_REQUIRE_EQUAL(17, b); + BOOST_REQUIRE_EQUAL(18, i); + BOOST_REQUIRE_EQUAL(18, b); } namespace { - const int iterations = getenv("ITERATIONS") ? atoi("ITERATIONS") : 1000000; + const int iterations = getenv("ITERATIONS") ? atoi(getenv("ITERATIONS")) : 1000000; std::atomic_int producer_count(0); std::atomic_int consumer_count(0); @@ -108,10 +108,10 @@ namespace { std::atomic done (false); } -void producer(async_queue& q, std::atomic_int& n, int i) +void producer(async_queue& q, int i) { for (int i = 0; i != iterations; ++i) { - int value = ++n; + int value = ++producer_count; while (!q.enqueue(value)); } @@ -131,16 +131,17 @@ BOOST_AUTO_TEST_CASE( test_async_queue_concurrent ) for (int i = 0; i < producer_thread_count; ++i) producer_threads.create_thread( - [&q, i] () { producer(*q, producer_count, i+1); } + [&q, i] () { producer(*q, i+1); } ); - while (q->async_dequeue( + while(q->async_dequeue( [] (int& v, const boost::system::error_code& ec) { - consumer_count++; - return consumer_count < total_iterations; + if (!ec) + ++consumer_count; + return !(done && consumer_count >= producer_count); }, std::chrono::milliseconds(1000), - true)); + -1)); io.run(); io.reset(); @@ -152,8 +153,10 @@ BOOST_AUTO_TEST_CASE( test_async_queue_concurrent ) std::cout << "Consumed " << consumer_count << " objects." << std::endl; } + bool abort = false; + auto r = q->async_dequeue( - [] (int& v, const boost::system::error_code& ec) { return true; }, + [&abort] (int& v, const boost::system::error_code& ec) { return !abort; }, std::chrono::milliseconds(8000), -1); @@ -161,8 +164,9 @@ BOOST_AUTO_TEST_CASE( test_async_queue_concurrent ) boost::asio::system_timer t(io); t.expires_from_now(std::chrono::milliseconds(1)); - t.async_wait([&q](const boost::system::error_code& e) { + t.async_wait([&q, &abort](const boost::system::error_code& e) { q->cancel(); + abort = true; if (eixx::verboseness::level() >= eixx::connect::VERBOSE_DEBUG) std::cout << "Canceled timer" << std::endl; }); diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 511b47f..3235c6b 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -241,6 +241,7 @@ BOOST_AUTO_TEST_CASE( test_list4 ) for (int i=0; i<2; ++i) l.push_back(eterm(atom("abc"))); l.close(); + BOOST_REQUIRE_EQUAL(2u, l.length()); } BOOST_AUTO_TEST_CASE( test_double ) @@ -351,10 +352,14 @@ BOOST_AUTO_TEST_CASE( test_pid ) BOOST_REQUIRE_EQUAL(1, et.id()); BOOST_REQUIRE_EQUAL(2, et.serial()); BOOST_REQUIRE_EQUAL(3, et.creation()); + + et = epid("abc@fc12", 1, 2, 4, alloc); + BOOST_REQUIRE_EQUAL(0, et.creation()); + eterm t(et); BOOST_REQUIRE(t.initialized()); BOOST_REQUIRE_EQUAL(PID, t.type()); - BOOST_REQUIRE_EQUAL("#Pid", t.to_string()); + BOOST_REQUIRE_EQUAL("#Pid", t.to_string()); } { @@ -431,17 +436,21 @@ BOOST_AUTO_TEST_CASE( test_ref ) { allocator_t alloc; { - uint32_t ids[] = {1,2,3}; - ref et("abc@fc12", ids, 4, alloc); + uint32_t ids[] = {5,6,7}; + ref et("abc@fc12", ids, 3, alloc); BOOST_REQUIRE_EQUAL(atom("abc@fc12"), et.node()); - BOOST_REQUIRE_EQUAL(1u, et.id(0)); - BOOST_REQUIRE_EQUAL(2u, et.id(1)); - BOOST_REQUIRE_EQUAL(3u, et.id(2)); - BOOST_REQUIRE_EQUAL(4, et.creation()); + BOOST_REQUIRE_EQUAL(5u, et.id(0)); + BOOST_REQUIRE_EQUAL(6u, et.id(1)); + BOOST_REQUIRE_EQUAL(7u, et.id(2)); + BOOST_REQUIRE_EQUAL(3, et.creation()); + + et = ref("abc@fc12", ids, 4, alloc); + BOOST_REQUIRE_EQUAL(0, et.creation()); + eterm t(et); BOOST_REQUIRE(t.initialized()); BOOST_REQUIRE_EQUAL(REF, t.type()); - BOOST_REQUIRE_EQUAL("#Ref", t.to_string()); + BOOST_REQUIRE_EQUAL("#Ref", t.to_string()); } { diff --git a/test/test_eterm_encode.cpp b/test/test_eterm_encode.cpp index a660fef..f541f4d 100644 --- a/test/test_eterm_encode.cpp +++ b/test/test_eterm_encode.cpp @@ -189,7 +189,7 @@ BOOST_AUTO_TEST_CASE( test_encode_ref ) { uint32_t ids[] = {1,2,3}; eterm t(ref("test@host", ids, 0)); - BOOST_REQUIRE_EQUAL("#Ref", t.to_string()); + BOOST_REQUIRE_EQUAL("#Ref", t.to_string()); string s(t.encode(0)); //std::cout << s.to_binary_string() << std::endl; const uint8_t expect[] = {131,114,0,3,100,0,9,116,101,115,116,64,104,111,115, diff --git a/test/test_eterm_match.cpp b/test/test_eterm_match.cpp index 224ce34..3b18922 100644 --- a/test/test_eterm_match.cpp +++ b/test/test_eterm_match.cpp @@ -417,17 +417,22 @@ BOOST_AUTO_TEST_CASE( test_match_list ) BOOST_AUTO_TEST_CASE( test_match_list_tail ) { BOOST_WARN_MESSAGE(false, "SKIPPING test_match_list_tail - needs extension to list matching!"); + BOOST_REQUIRE(true); // don't print the warning return; + static const atom A("A"); + static const atom O("O"); + static const atom T("T"); + eterm pattern = eterm::format("[{A, O} | T]"); eterm term = eterm::format("[{a, 1}, {b, ok}, {c, 2.0}]"); varbind vars; // Match [{a, 1} | T] BOOST_REQUIRE(pattern.match(term, &vars)); - const eterm* name = vars.find("A"); - const eterm* value = vars.find("O"); - const eterm* tail = vars.find("T"); + const eterm* name = vars.find(A); + const eterm* value = vars.find(O); + const eterm* tail = vars.find(T); BOOST_REQUIRE(name != NULL); BOOST_REQUIRE(value != NULL); @@ -441,9 +446,9 @@ BOOST_AUTO_TEST_CASE( test_match_list_tail ) // Match [{b, ok} | T] vars.clear(); BOOST_REQUIRE(term.match(*tail, &vars)); - name = vars.find("A"); - value = vars.find("O"); - tail = vars.find("T"); + name = vars.find(A); + value = vars.find(O); + tail = vars.find(T); BOOST_REQUIRE(name != NULL); BOOST_REQUIRE(value != NULL); @@ -457,9 +462,9 @@ BOOST_AUTO_TEST_CASE( test_match_list_tail ) // Match [{c, 2.0} | T] vars.clear(); BOOST_REQUIRE(term.match(*tail, &vars)); - name = vars.find("A"); - value = vars.find("O"); - tail = vars.find("T"); + name = vars.find(A); + value = vars.find(O); + tail = vars.find(T); BOOST_REQUIRE(name != NULL); BOOST_REQUIRE(value != NULL); From 4034d5782cbf6ae001fbb967730f896d7a223075 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 27 Nov 2013 09:10:11 -0500 Subject: [PATCH 013/185] Moved code to implementation --- include/eixx/connect/basic_otp_node.hpp | 62 +++++++---------------- include/eixx/connect/basic_otp_node.ipp | 66 +++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 43 deletions(-) diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index c909e6d..75ac443 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -100,13 +100,10 @@ class basic_otp_node: public basic_otp_node_local { friend class basic_otp_connection; void on_disconnect_internal(const connection_t& a_con, - atom a_remote_nodename, const boost::system::error_code& err) - { - if (on_disconnect) - on_disconnect(*this, a_con, a_remote_nodename, err); - } + atom a_remote_nodename, const boost::system::error_code& err); - void report_status(report_level a_level, const connection_t* a_con, const std::string& s); + void report_status(report_level a_level, + const connection_t* a_con, const std::string& s); void rpc_call(const epid& a_from, const ref& a_ref, const atom& a_mod, const atom& a_fun, const list& a_args, const eterm& a_gleader); @@ -118,10 +115,11 @@ class basic_otp_node: public basic_otp_node_local { /// Unregister this node from epmd. void unpublish_port() throw (err_connection); - /// Send a message to a process ToProc which is either epid or + /// Send a message to a process ToProc which is either epid or /// atom for registered names. template - void send(const atom& a_to_node, ToProc a_to, const transport_msg& a_msg) + void send(const atom& a_to_node, + ToProc a_to, const transport_msg& a_msg) throw (err_no_process, err_connection); public: typedef basic_otp_mailbox_registry mailbox_registry_t; @@ -133,7 +131,7 @@ class basic_otp_node: public basic_otp_node_local { * hostname and port. ex: "ei:mynode@host.somewhere.com:3128" * @param a_cookie cookie to use * @param a_alloc is the allocator to use - * @param a_creation is the creation value to use (0 .. 2). This + * @param a_creation is the creation value to use (0 .. 2). This * argument is provided for being able to do determinitic testing. * In production pass the default value, so that the creation value * is determined automatically. @@ -151,11 +149,7 @@ class basic_otp_node: public basic_otp_node_local { virtual ~basic_otp_node() { close(); } /// Change name of current node - void set_nodename(const atom& a_nodename, const std::string& a_cookie = "") { - close(); - if (a_nodename != atom()) - basic_otp_node_local::set_nodename(a_nodename.to_string(), a_cookie); - } + void set_nodename(const atom& a_nodename, const std::string& a_cookie = ""); /// Get current verboseness level verbose_type verbose() const { return m_verboseness; } @@ -167,16 +161,13 @@ class basic_otp_node: public basic_otp_node_local { /// Get the service object used by this node. boost::asio::io_service& io_service() { return m_io_service; } + /// Run the node's service dispatch void run() { m_io_service.run(); } + /// Stop the node's service dispatch void stop() { m_io_service.stop(); } - void close() { - m_mailboxes.clear(); - for(typename conn_hash_map::iterator - it = m_connections.begin(), end = m_connections.end(); it != end; ++it) - it->second->disconnect(); - m_connections.clear(); - } + /// Close all connections and empty the mailbox + void close(); /** * Create a new mailbox with a new mailbox that can be used to send and @@ -188,16 +179,9 @@ class basic_otp_node: public basic_otp_node_local { * @return new mailbox with a new pid. */ basic_otp_mailbox* - create_mailbox(const atom& a_reg_name = atom(), boost::asio::io_service* a_svc = NULL) { - boost::asio::io_service* p_svc = a_svc ? a_svc : &m_io_service; - return m_mailboxes.create_mailbox(a_reg_name, p_svc); - } + create_mailbox(const atom& a_name = atom(), boost::asio::io_service* a_svc = NULL); - void close_mailbox(basic_otp_mailbox* a_mbox) { - if (a_mbox) { - m_mailboxes.erase(a_mbox); - } - } + void close_mailbox(basic_otp_mailbox* a_mbox); /// Get a mailbox associated with a given atom name or epid. /// @param a_proc is either an atom name of a registered local process or epid. @@ -255,19 +239,11 @@ class basic_otp_node: public basic_otp_node_local { */ template void connect(CompletionHandler h, const atom& a_remote_nodename, - size_t a_reconnect_secs = 0) throw(err_connection) - { - connect(h, a_remote_nodename, atom(), a_reconnect_secs); - } + size_t a_reconnect_secs = 0) throw(err_connection); /// Get connection identified by the \a a_node name. /// @throws err_connection if not connected to \a a_node._ - connection_t& connection(atom a_nodename) const { - auto l_con = m_connections.find(a_nodename); - if (l_con == m_connections.end()) - throw err_connection("Not connected to node", a_nodename); - return *l_con->second.get(); - } + connection_t& connection(atom a_nodename) const; /** * Callback invoked on disconnect from a peer node @@ -275,16 +251,16 @@ class basic_otp_node: public basic_otp_node_local { boost::function< // OtpNode OtpConnection RemoteNodeName ErrorCode void (self&, const connection_t&, atom, const boost::system::error_code&) - > on_disconnect; + > on_disconnect; /** * Callback invoked if verbosity is different from VERBOSE_NONE. If not assigned, - * the content is printed to stderr. + * the content is printed to stderr. */ boost::function< // OtpNode OtpConnection Status Message void (self&, const connection_t*, report_level, const std::string&) - > on_status; + > on_status; boost::function< eterm (const epid& a_from, const ref& a_ref, diff --git a/include/eixx/connect/basic_otp_node.ipp b/include/eixx/connect/basic_otp_node.ipp index bad0f12..3ee1a7f 100644 --- a/include/eixx/connect/basic_otp_node.ipp +++ b/include/eixx/connect/basic_otp_node.ipp @@ -152,6 +152,64 @@ create_ref() return ref(m_nodename, mn, n, m_creation, m_allocator); } +template +inline basic_otp_mailbox* +basic_otp_node:: +create_mailbox(const atom& a_name, boost::asio::io_service* a_svc) +{ + boost::asio::io_service* p_svc = a_svc ? a_svc : &m_io_service; + return m_mailboxes.create_mailbox(a_name, p_svc); +} + +template +void basic_otp_node:: +close_mailbox(basic_otp_mailbox* a_mbox) +{ + if (a_mbox) + m_mailboxes.erase(a_mbox); +} + + +template +void basic_otp_node:: +set_nodename(const atom& a_nodename, const std::string& a_cookie) +{ + close(); + if (a_nodename != atom()) + basic_otp_node_local::set_nodename(a_nodename.to_string(), a_cookie); +} + +template +void basic_otp_node:: +close() +{ + m_mailboxes.clear(); + for(typename conn_hash_map::iterator + it = m_connections.begin(), end = m_connections.end(); it != end; ++it) + it->second->disconnect(); + m_connections.clear(); +} + +template +template +inline void basic_otp_node:: +connect(CompletionHandler h, const atom& a_remote_nodename, size_t a_reconnect_secs) + throw(err_connection) +{ + connect(h, a_remote_nodename, atom(), a_reconnect_secs); +} + +template +inline typename basic_otp_node::connection_t& +basic_otp_node:: +connection(atom a_nodename) const +{ + auto l_con = m_connections.find(a_nodename); + if (l_con == m_connections.end()) + throw err_connection("Not connected to node", a_nodename); + return *l_con->second.get(); +} + template template void basic_otp_node:: @@ -172,6 +230,14 @@ connect(CompletionHandler h, const atom& a_remote_node, const atom& a_cookie, } } +template +void basic_otp_node:: +on_disconnect_internal(const connection_t& a_con, + atom a_remote_nodename, const boost::system::error_code& err) +{ + if (on_disconnect) + on_disconnect(*this, a_con, a_remote_nodename, err); +} template void basic_otp_node:: From 693539e3589149170f441d71d65998c88954f2a3 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 27 Nov 2013 09:31:37 -0500 Subject: [PATCH 014/185] Readme reformatted --- README | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/README b/README index 4cf7423..b0340c1 100644 --- a/README +++ b/README @@ -1,5 +1,4 @@ -eixx - Erlang C++ Interface Library -=================================== +# eixx - Erlang C++ Interface Library # This library provides a set of classes for convenient marshaling of Erlang terms between processes as well as connecting to other @@ -32,14 +31,14 @@ Ths library is dependend on {@link http://www.boost.org BOOST} project and erl_interface, which is a part of the {@link www.erlang.org Erlang} distribution. -Downloading -=========== +## Downloading ## + Repository location: http://github.com/saleyn/eixx $ git clone git@github.com:saleyn/eixx.git -Building -======== +## Building ## + Make sure that you have autoconf-archive package installed: http://www.gnu.org/software/autoconf-archive @@ -50,16 +49,15 @@ Building $ make $ make install # Default install path is ./install -Author -====== +## Author ## + Serge Aleynikov -LICENSE -======= +## LICENSE ## + GNU Lesser General Public License -Example -======= +## Example ## Manipulating Erlang terms is quite simple: From fe181a9067e242eb49921780276c179f0c70a40e Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 27 Nov 2013 09:35:16 -0500 Subject: [PATCH 015/185] Renamed readme --- README => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README => README.md (100%) diff --git a/README b/README.md similarity index 100% rename from README rename to README.md From 8c1a73cc4be9d548edd74fce61f8dd4382a7a85d Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 27 Nov 2013 09:39:55 -0500 Subject: [PATCH 016/185] Redacted readme --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b0340c1..50fa21d 100644 --- a/README.md +++ b/README.md @@ -33,16 +33,16 @@ project and erl_interface, which is a part of the ## Downloading ## - Repository location: http://github.com/saleyn/eixx +Repository location: http://github.com/saleyn/eixx $ git clone git@github.com:saleyn/eixx.git ## Building ## - Make sure that you have autoconf-archive package installed: - http://www.gnu.org/software/autoconf-archive +Make sure that you have autoconf-archive package installed: +[http://www.gnu.org/software/autoconf-archive] - Run: +Run: $ ./bootstrap $ ./configure --with-boost="/path/to/boost" [--with-erlang="/path/to/erlang"] \ [--prefix="/target/install/path"] @@ -51,11 +51,11 @@ project and erl_interface, which is a part of the ## Author ## - Serge Aleynikov +Serge Aleynikov ## LICENSE ## - GNU Lesser General Public License +GNU Lesser General Public License ## Example ## From 4bdf97c9b7b33db912bca54098108d8d4173ee81 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 27 Nov 2013 09:43:33 -0500 Subject: [PATCH 017/185] Redacted readme --- README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 50fa21d..9e3d60c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# eixx - Erlang C++ Interface Library # +## eixx - Erlang C++ Interface Library ## This library provides a set of classes for convenient marshaling of Erlang terms between processes as well as connecting to other @@ -31,16 +31,16 @@ Ths library is dependend on {@link http://www.boost.org BOOST} project and erl_interface, which is a part of the {@link www.erlang.org Erlang} distribution. -## Downloading ## +### Downloading ### Repository location: http://github.com/saleyn/eixx $ git clone git@github.com:saleyn/eixx.git -## Building ## +### Building ### -Make sure that you have autoconf-archive package installed: -[http://www.gnu.org/software/autoconf-archive] +Make sure that you have [autoconf-archive] +(http://www.gnu.org/software/autoconf-archive) package installed. Run: $ ./bootstrap @@ -49,15 +49,15 @@ Run: $ make $ make install # Default install path is ./install -## Author ## +### Author ### Serge Aleynikov -## LICENSE ## +### LICENSE ### GNU Lesser General Public License -## Example ## +### Example ### Manipulating Erlang terms is quite simple: @@ -164,8 +164,7 @@ Here's an example use of the eixx library: -Testing distributed transport -============================= +### Testing distributed transport ### $ make From c40b121734d267d4c660a09c98416fef377730bb Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 27 Nov 2013 09:49:02 -0500 Subject: [PATCH 018/185] Redacted readme --- README.md | 162 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 83 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 9e3d60c..3dafd16 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Make sure that you have [autoconf-archive] (http://www.gnu.org/software/autoconf-archive) package installed. Run: + $ ./bootstrap $ ./configure --with-boost="/path/to/boost" [--with-erlang="/path/to/erlang"] \ [--prefix="/target/install/path"] @@ -60,113 +61,116 @@ GNU Lesser General Public License ### Example ### Manipulating Erlang terms is quite simple: - - eterm i = 10; - eterm s = "abc"; - eterm a = atom("ok"); - eterm t = {20.0, i, s, a}; // Constructs a tuple - eterm e = list{}; // Constructs an empty list - eterm l = list{i, 100.0, s, {a, 30}, list{}}; // Constructs a list - - A convenient eterm::format() function implements an expression parser: - - eterm t1 = eterm::format("{ok, 10}"); - eterm t2 = eterm::format("[1, 2, ok, [{one, 10}, {two, 20}]]"); - eterm t3 = eterm::format("A::int()"); // t3 is a variable that can be matched +```cpp +eterm i = 10; +eterm s = "abc"; +eterm a = atom("ok"); +eterm t = {20.0, i, s, a}; // Constructs a tuple +eterm e = list{}; // Constructs an empty list +eterm l = list{i, 100.0, s, {a, 30}, list{}}; // Constructs a list +``` +A convenient eterm::format() function implements an expression parser: + +```cpp +eterm t1 = eterm::format("{ok, 10}"); +eterm t2 = eterm::format("[1, 2, ok, [{one, 10}, {two, 20}]]"); +eterm t3 = eterm::format("A::int()"); // t3 is a variable that can be matched +``` Pattern matching is done by constructing a pattern, and matching a term against it. If varbind is provided, it'll store the values of all matched variables: - static const eterm s_pattern = eterm::format("{ok, A::string()}"); +```cpp +static const eterm s_pattern = eterm::format("{ok, A::string()}"); - eterm value = {atom("ok"), "abc"}; +eterm value = {atom("ok"), "abc"}; - varbind binding; - - if (value.match(s_pattern, &binding)) - std::cout << "Value of variable A: " << binding["A"].to_string() << std::endl; +varbind binding; +if (value.match(s_pattern, &binding)) + std::cout << "Value of variable A: " << binding["A"].to_string() << std::endl; +``` Aside from providing functionality that allows to manipulate Erlang terms, this library implements Erlang distributed transport that allows a C++ program to connect to an Erlang node, exchange messages, make RPC calls, and receive I/O requests. Here's an example use of the eixx library: - void on_message(otp_mailbox& a_mbox, boost::system::error_code& ec) { - // On timeout ec == boost::asio::error::timeout - if (ec == boost::asio::error::timeout) { - std::cout << "Mailbox " << a_mbox.self() << " timeout: " - << ec.message() << std::endl; - } else { - // The mailbox has a queue of transport messages. - // Dequeue next message from the mailbox. - std::unique_ptr dist_msg; - - while (dist_msg.reset(a_mbox.receive())) { - std::cout << "Main mailbox got a distributed transport message:\n " - << *dist_msg << std::endl; - - // Compile the following pattern into the corresponding abstract tree. - // The expression must be a valid Erlang term - static const eterm s_pattern = eterm::format("{From, {command, Cmd}}"); - - varbind binding; - - // Pattern match the message and bind From and Cmd variables - if (dist_msg->msg().match(s_pattern, &binding)) { - const eterm* cmd = binding->find("Cmd"); - std::cout << "Got a command " << *cmd << std::endl; - // Process command, e.g.: - // process_command(binding["From"]->to_pid(), *cmd); - } +```cpp +void on_message(otp_mailbox& a_mbox, boost::system::error_code& ec) { + // On timeout ec == boost::asio::error::timeout + if (ec == boost::asio::error::timeout) { + std::cout << "Mailbox " << a_mbox.self() << " timeout: " + << ec.message() << std::endl; + } else { + // The mailbox has a queue of transport messages. + // Dequeue next message from the mailbox. + std::unique_ptr dist_msg; + + while (dist_msg.reset(a_mbox.receive())) { + std::cout << "Main mailbox got a distributed transport message:\n " + << *dist_msg << std::endl; + + // Compile the following pattern into the corresponding abstract tree. + // The expression must be a valid Erlang term + static const eterm s_pattern = eterm::format("{From, {command, Cmd}}"); + + varbind binding; + + // Pattern match the message and bind From and Cmd variables + if (dist_msg->msg().match(s_pattern, &binding)) { + const eterm* cmd = binding->find("Cmd"); + std::cout << "Got a command " << *cmd << std::endl; + // Process command, e.g.: + // process_command(binding["From"]->to_pid(), *cmd); } } - - // Schedule next async receive of a message (can also provide a timeout). - a_mbox.async_receive(&on_message); + } + + // Schedule next async receive of a message (can also provide a timeout). + a_mbox.async_receive(&on_message); +} + +void on_connect(otp_connection* a_con, const std::string& a_error) { + if (!a_error.empty()) { + std::cout << a_error << std::endl; + return; } - void on_connect(otp_connection* a_con, const std::string& a_error) { - if (!a_error.empty()) { - std::cout << a_error << std::endl; - return; - } - - // Illustrate creation of Erlang terms. - eterm t1 = eterm::format("{ok, ~i}", 10); - eterm t2 = tuple::make(10, 1.0, atom("test"), "abc"); - eterm t3("This is a string"); - eterm t4(tuple::make(t1, t2, t3)); - - otp_node* node = a_con->node(); - otp_mailbox* mbox = node->get_mailbox("main"); - - // Send a message: {{ok, 10}, {10, 1.0, 'test', "abc"}, "This is a string"} - // to an Erlang process named 'test' running - // on node "abc@myhost" + // Illustrate creation of Erlang terms. + eterm t1 = eterm::format("{ok, ~i}", 10); + eterm t2 = tuple::make(10, 1.0, atom("test"), "abc"); + eterm t3("This is a string"); + eterm t4(tuple::make(t1, t2, t3)); - node->send(mbox.self(), a_con->remote_node(), atom("test"), t4); - } + otp_node* node = a_con->node(); + otp_mailbox* mbox = node->get_mailbox("main"); - int main() { - use namespace eixx; + // Send a message: {{ok, 10}, {10, 1.0, 'test', "abc"}, "This is a string"} + // to an Erlang process named 'test' running + // on node "abc@myhost" - otp_node node("abc"); + node->send(mbox.self(), a_con->remote_node(), atom("test"), t4); +} - otp_mailbox* mbox = node.create_mailbox("main"); +int main() { + use namespace eixx; - node.connect(&on_connect, "abc@myhost"); + otp_node node("abc"); - // Asynchronously receive a message with a deadline of 10s: - mbox->async_receive(&on_message, 10000); + otp_mailbox* mbox = node.create_mailbox("main"); - node.run(); - } + node.connect(&on_connect, "abc@myhost"); + // Asynchronously receive a message with a deadline of 10s: + mbox->async_receive(&on_message, 10000); + node.run(); +} +``` ### Testing distributed transport ### -$ make + $ make Run tests: From 37ce661b43677b1ddaff5a9ef8fed22b5a3fca8c Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 27 Nov 2013 22:32:06 -0500 Subject: [PATCH 019/185] Fixed make install --- Makefile.am | 2 +- src/Makefile.am | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index 85f44c4..861bb8e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,6 +29,6 @@ EXTRA_DIST = README LICENSE LICENSE.header license.sh \ bootstrap installdir = $(prefix) -install_DATA = README LICENSE +install_DATA = README.md LICENSE .PHONY: docs doc diff --git a/src/Makefile.am b/src/Makefile.am index ba649b2..1c2eacd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,13 +9,17 @@ eixx_hdrs1 = alloc_pool.hpp \ connect.hpp \ eixx.hpp \ eterm.hpp \ - eterm_exception.hpp + eterm_exception.hpp \ + namespace.hpp eixx_hdrs2 = connect/basic_otp_connection.hpp \ connect/basic_otp_mailbox.hpp \ + connect/basic_otp_mailbox.ipp \ connect/basic_otp_mailbox_registry.hpp \ + connect/basic_otp_mailbox_registry.ipp \ connect/basic_otp_node.hpp \ connect/basic_otp_node.ipp \ connect/basic_otp_node_local.hpp \ + connect/detail/basic_rpc_server.hpp \ connect/test_helper.hpp \ connect/transport_msg.hpp \ connect/transport_otp_connection.hpp \ @@ -56,11 +60,15 @@ eixx_hdrs3 = marshal/alloc_base.hpp \ marshal/visit_match.hpp \ marshal/visit_subst.hpp \ marshal/visit_to_string.hpp -eixx_hdrs4 = util/async_wait_timeout.hpp \ +eixx_hdrs4 = util/async_queue.hpp \ + util/async_wait_timeout.hpp \ + util/atom_table.hpp \ util/common.hpp \ + util/compiler_hints.hpp \ util/hashtable.hpp \ util/string_util.hpp \ - util/sync.hpp + util/sync.hpp \ + util/timeout.hpp eixx_headers= $(eixx_hdrs1) \ $(eixx_hdrs2) \ From 1b43ecc00c93f362beb0b3b36dd2fcd8ebbbee60 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 18 Mar 2014 08:29:38 -0400 Subject: [PATCH 020/185] Replaced atom_table::string_t with std::string --- include/eixx/marshal/atom.hpp | 33 ++++++------- include/eixx/marshal/pid.ipp | 2 +- include/eixx/marshal/port.ipp | 2 +- include/eixx/marshal/ref.ipp | 2 +- include/eixx/marshal/var.hpp | 6 +-- include/eixx/util/atom_table.hpp | 82 ++++++-------------------------- include/eixx/util/hashtable.hpp | 4 +- include/eixx/util/sync.hpp | 4 +- src/atom.cpp | 4 +- test/test_eterm.cpp | 2 +- 10 files changed, 43 insertions(+), 98 deletions(-) diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 3496562..73a9d08 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -72,9 +72,7 @@ class atom int m_index; public: - typedef util::atom_table<>::string_t string_t; - - static util::atom_table<>& atom_table(); + static util::atom_table& atom_table(); /// Returns empty atom static const atom null; @@ -89,12 +87,12 @@ class atom /// @throws std::runtime_error if atom table is full. /// @throws err_bad_argument if atom size is longer than MAXATOMLEN atom(const char* s) throw(std::runtime_error, err_bad_argument) - : m_index(atom_table().lookup(string_t(s))) {} + : m_index(atom_table().lookup(std::string(s))) {} /// @copydoc atom::atom template atom(const char (&s)[N]) throw(std::runtime_error, err_bad_argument) - : m_index(atom_table().lookup(string_t(s, N))) {} + : m_index(atom_table().lookup(std::string(s, N))) {} /// @copydoc atom::atom explicit atom(const std::string& s) throw(std::runtime_error) @@ -104,12 +102,12 @@ class atom /// @copydoc atom::atom template explicit atom(const string& s) throw(std::runtime_error) - : m_index(atom_table().lookup(string_t(s.c_str(), s.size()))) + : m_index(atom_table().lookup(std::string(s.c_str(), s.size()))) {} /// @copydoc atom::atom atom(const char* s, size_t n) throw(std::runtime_error) - : m_index(atom_table().lookup(string_t(s, n))) + : m_index(atom_table().lookup(std::string(s, n))) {} /// Copy atom from another atom. This is a constant time @@ -123,19 +121,22 @@ class atom { const char *s = a_buf + idx; const char *s0 = s; - if (get8(s) != ERL_ATOM_EXT) - throw err_decode_exception("Error decoding atom", idx); - int len = get16be(s); - m_index = atom_table().lookup(string_t(s, len)); + int len; + switch (get8(s)) { + case ERL_ATOM_EXT: len = get16be(s); break; + case ERL_SMALL_ATOM_EXT: len = get8(s); break; + default: throw err_decode_exception("Error decoding atom", idx); + } + m_index = atom_table().lookup(std::string(s, len)); idx += s + len - s0; BOOST_ASSERT((size_t)idx <= a_size); } - const char* c_str() const { return atom_table()[m_index].c_str(); } - const string_t& to_string() const { return atom_table()[m_index]; } - size_t size() const { return atom_table()[m_index].size(); } - size_t length() const { return size(); } - bool empty() const { return m_index == 0; } + const char* c_str() const { return atom_table()[m_index].c_str(); } + const std::string& to_string() const { return atom_table()[m_index]; } + size_t size() const { return atom_table()[m_index].size(); } + size_t length() const { return size(); } + bool empty() const { return m_index == 0; } /// Get atom's index in the atom table. int index() const { return m_index; } diff --git a/include/eixx/marshal/pid.ipp b/include/eixx/marshal/pid.ipp index 70c287c..6090931 100644 --- a/include/eixx/marshal/pid.ipp +++ b/include/eixx/marshal/pid.ipp @@ -69,7 +69,7 @@ void epid::encode(char* buf, int& idx, size_t size) const char* s0 = s; put8(s,ERL_PID_EXT); put8(s,ERL_ATOM_EXT); - const atom::string_t& nd = node().to_string(); + const std::string& nd = node().to_string(); unsigned short n = nd.size(); put16be(s, n); memmove(s, nd.c_str(), n); diff --git a/include/eixx/marshal/port.ipp b/include/eixx/marshal/port.ipp index 6c02a9d..9893c9e 100644 --- a/include/eixx/marshal/port.ipp +++ b/include/eixx/marshal/port.ipp @@ -64,7 +64,7 @@ void port::encode(char* buf, int& idx, size_t size) const char* s0 = s; put8(s,ERL_PORT_EXT); put8(s,ERL_ATOM_EXT); - const atom::string_t& str = node().to_string(); + const std::string& str = node().to_string(); unsigned short n = str.size(); put16be(s, n); memmove(s, str.c_str(), n); diff --git a/include/eixx/marshal/ref.ipp b/include/eixx/marshal/ref.ipp index 5c21cf6..607602f 100644 --- a/include/eixx/marshal/ref.ipp +++ b/include/eixx/marshal/ref.ipp @@ -83,7 +83,7 @@ void ref::encode(char* buf, int& idx, size_t size) const put16be(s, COUNT); /* then the nodename */ put8(s,ERL_ATOM_EXT); - const atom::string_t& str = node().to_string(); + const std::string& str = node().to_string(); unsigned short n = str.size(); put16be(s, n); memmove(s, str.c_str(), n); diff --git a/include/eixx/marshal/var.hpp b/include/eixx/marshal/var.hpp index 6d64f9d..f6bb0c9 100644 --- a/include/eixx/marshal/var.hpp +++ b/include/eixx/marshal/var.hpp @@ -58,8 +58,6 @@ class var return is_any() || m_type == UNDEFINED || t == m_type; } - typedef util::atom_table<>::string_t string_t; - eterm_type set(eterm_type t) { return m_name == am_ANY_ ? UNDEFINED : t; } public: @@ -74,14 +72,14 @@ class var var(const var& v) : var(v.name(), v.type()) {} const char* c_str() const { return m_name.c_str(); } - const string_t& str() const { return m_name.to_string(); } + const std::string& str() const { return m_name.to_string(); } atom name() const { return m_name; } size_t length() const { return m_name.length(); } eterm_type type() const { return (eterm_type)m_type; } bool is_any() const { return name() == am_ANY_; } - string_t to_string() const { + std::string to_string() const { std::stringstream s; s << name().to_string() << type_to_type_string(type(), true); return s.str(); diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 42dbe52..6e4685c 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -55,64 +55,8 @@ namespace util { /// and its content is never cleared. The table contains a unique /// list of strings represented as atoms added throughout the lifetime /// of the application. - template - class atom_table { - public: - //typedef std::basic_string, Alloc> string_t; - typedef std::string string_t; - private: - // See http://www.azillionmonkeys.com/qed/hash.html - // Copyright 2004-2008 (c) by Paul Hsieh - struct hsieh_hash_fun { - static uint16_t get16bits(const char* d) { return *(const uint16_t *)d; } - - int operator()(const char* data) const { - int len = strlen(data); - uint32_t hash = len, tmp; - int rem; - - if (len <= 0 || data == NULL) return 0; - - rem = len & 3; - len >>= 2; - - /* Main loop */ - for (;len > 0; len--) { - hash += get16bits (data); - tmp = (get16bits (data+2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2*sizeof (uint16_t); - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) { - case 3: hash += get16bits (data); - hash ^= hash << 16; - hash ^= data[sizeof (uint16_t)] << 18; - hash += hash >> 11; - break; - case 2: hash += get16bits (data); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: hash += *data; - hash ^= hash << 10; - hash += hash >> 1; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; - } - }; - + template + class basic_atom_table : private detail::hsieh_hash_fun { static const int s_default_max_atoms = 1024*1024; int find_value(size_t bucket, const char* a_atom) { @@ -136,24 +80,24 @@ namespace util { /// Returns the current number of atoms stored in the atom table. size_t allocated() const { return m_atoms.size(); } - explicit atom_table(int a_max_atoms = default_size()) + explicit basic_atom_table(int a_max_atoms = default_size()) : m_index(a_max_atoms) { m_atoms.reserve(a_max_atoms); m_atoms.push_back(""); // The 0-th element is an empty atom (""). m_index[""] = 0; } - ~atom_table() { + ~basic_atom_table() { lock_guard guard(m_lock); m_atoms.clear(); m_index.clear(); } /// Lookup an atom in the atom table by index. - const string_t& get(int n) const { return (*this)[n]; } + const String& get(int n) const { return (*this)[n]; } /// Lookup an atom in the atom table by index. - const string_t& operator[] (int n) const { + const String& operator[] (int n) const { BOOST_ASSERT((size_t)n < m_atoms.size()); return m_atoms[n]; } @@ -163,9 +107,9 @@ namespace util { /// atom in the atom table. /// @throws std::runtime_error if atom table is full. /// @throws err_bad_argument if atom size is longer than MAXATOMLEN - int lookup(const char* a_name, size_t n) { return lookup(std::string(a_name, n)); } - int lookup(const char* a_name) { return lookup(std::string(a_name)); } - int lookup(const std::string& a_name) + int lookup(const char* a_name, size_t n) { return lookup(String(a_name, n)); } + int lookup(const char* a_name) { return lookup(String(a_name)); } + int lookup(const String& a_name) throw(std::runtime_error, err_bad_argument) { if (a_name.size() == 0) @@ -190,11 +134,13 @@ namespace util { return n; } private: - std::vector m_atoms; - char_int_hash_map m_index; - Mutex m_lock; + std::vector m_atoms; + char_int_hash_map m_index; + Mutex m_lock; }; + typedef basic_atom_table<> atom_table; + } // namespace util } // namespace EIXX_NAMESPACE diff --git a/include/eixx/util/hashtable.hpp b/include/eixx/util/hashtable.hpp index 8caf2de..b7f1461 100644 --- a/include/eixx/util/hashtable.hpp +++ b/include/eixx/util/hashtable.hpp @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include -#ifdef __GXX_EXPERIMENTAL_CXX0X__ +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L #include #else #include @@ -36,7 +36,7 @@ namespace EIXX_NAMESPACE { namespace detail { namespace src = - #ifdef __GXX_EXPERIMENTAL_CXX0X__ + #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L std; #else boost; diff --git a/include/eixx/util/sync.hpp b/include/eixx/util/sync.hpp index a5cc62c..8629880 100644 --- a/include/eixx/util/sync.hpp +++ b/include/eixx/util/sync.hpp @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include -#ifdef __GXX_EXPERIMENTAL_CXX0X__ +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L #include #else #include @@ -35,7 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace EIXX_NAMESPACE { namespace detail { -#ifdef __GXX_EXPERIMENTAL_CXX0X__ +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L typedef std::mutex mutex; typedef std::recursive_mutex recursive_mutex; template struct lock_guard: public std::lock_guard { diff --git a/src/atom.cpp b/src/atom.cpp index 9b5b114..fdf068e 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -28,9 +28,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace EIXX_NAMESPACE { - util::atom_table<>& marshal::atom::atom_table() { + util::atom_table& marshal::atom::atom_table() { //return boost::details::pool::singleton_default >::instance(); - static util::atom_table<> s_atom_table; + static util::atom_table s_atom_table; return s_atom_table; } diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 3235c6b..10e9d80 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -32,7 +32,7 @@ using namespace eixx; BOOST_AUTO_TEST_CASE( test_atomable ) { - util::atom_table<> t(10); + util::atom_table t(10); BOOST_REQUIRE_EQUAL(0, t.lookup(std::string())); BOOST_REQUIRE_EQUAL(0, t.lookup("")); int n = t.lookup("abc"); From caf60d3226a47c25016634b004ee5e6cafa850c7 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Fri, 21 Mar 2014 13:26:49 -0400 Subject: [PATCH 021/185] Cleanup of atom table --- configure.ac | 2 +- include/eixx/config.h | 6 +++--- include/eixx/util/atom_table.hpp | 18 ++++++++++++------ src/Makefile.am | 9 +++++++-- src/eixx.pc.in | 2 +- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 731dde5..c25c3f5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # -*- Autoconf -*- AC_PREREQ([2.63]) -AC_INIT([eixx], [0.1], [BUG-REPORT-ADDRESS]) +AC_INIT([eixx], [1.1], [BUG-REPORT-ADDRESS]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux]) AM_INIT_AUTOMAKE([foreign -Wall -Wno-portability]) diff --git a/include/eixx/config.h b/include/eixx/config.h index 1de7a2f..dcbba69 100644 --- a/include/eixx/config.h +++ b/include/eixx/config.h @@ -234,7 +234,7 @@ /* Define to the full name and version of this package. */ #ifndef EIXX_PACKAGE_STRING -#define EIXX_PACKAGE_STRING "eixx 0.1" +#define EIXX_PACKAGE_STRING "eixx 1.1" #endif /* Define to the one symbol short name of this package. */ @@ -249,7 +249,7 @@ /* Define to the version of this package. */ #ifndef EIXX_PACKAGE_VERSION -#define EIXX_PACKAGE_VERSION "0.1" +#define EIXX_PACKAGE_VERSION "1.1" #endif /* Define to 1 if you have the ANSI C header files. */ @@ -259,7 +259,7 @@ /* Version number of package */ #ifndef EIXX_VERSION -#define EIXX_VERSION "0.1" +#define EIXX_VERSION "1.1" #endif /* Define for Solaris 2.5.1 so the uint32_t typedef from , diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 6e4685c..75d6534 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -55,12 +55,18 @@ namespace util { /// and its content is never cleared. The table contains a unique /// list of strings represented as atoms added throughout the lifetime /// of the application. - template + template + < + typename String = std::string, + typename Vector = std::vector, + typename HashMap = char_int_hash_map, + typename Mutex = eid::mutex + > class basic_atom_table : private detail::hsieh_hash_fun { static const int s_default_max_atoms = 1024*1024; int find_value(size_t bucket, const char* a_atom) { - typename char_int_hash_map::const_local_iterator + typename HashMap::const_local_iterator lit = m_index.begin(bucket), lend = m_index.end(bucket); while(lit != lend && strcmp(a_atom, lit->first) != 0) ++lit; return lit == lend ? -1 : lit->second; @@ -125,7 +131,7 @@ namespace util { n = find_value(bucket, a_name.c_str()); if (n >= 0) return n; - + n = m_atoms.size(); if ((size_t)(n+1) == m_atoms.capacity()) throw std::runtime_error("Atom hash table is full!"); @@ -134,9 +140,9 @@ namespace util { return n; } private: - std::vector m_atoms; - char_int_hash_map m_index; - Mutex m_lock; + Vector m_atoms; + HashMap m_index; + Mutex m_lock; }; typedef basic_atom_table<> atom_table; diff --git a/src/Makefile.am b/src/Makefile.am index 1c2eacd..f9d429a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,6 @@ +# vim:tw=2 tw=2 +# + eixx_LTLIBRARIES = libeixx.la bin_PROGRAMS = test_node @@ -87,9 +90,11 @@ libeixx_la_hdr4_HEADERS = $(eixx_hdrs4:%=../include/@PACKAGE@/%) libeixx_la_SOURCES = am.cpp atom.cpp defaults.cpp ref.cpp \ basic_otp_node_local.cpp \ $(eixx_headers:%=../include/@PACKAGE@/%) -libeixx_la_LTADD = -version-info 0:1 -shared +libeixx_la_LTADD = -version-info 1:1:0 -shared libeixx_la_LIBS = $(BOOST_THREAD_LIB) $(CRYPTO_LIBS) -libeixx_la_CXXFLAGS = $(if $(tr1),-std=c++0x) -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) -I../include $(BOOST_CPPFLAGS) \ +libeixx_la_CXXFLAGS = $(if $(tr1),-std=c++0x) \ + -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ + -I../include $(BOOST_CPPFLAGS) \ $(EI_CPPFLAGS) #EXTRA_DIST = ../README overview.inl overview_usage.inl overview_config.inl diff --git a/src/eixx.pc.in b/src/eixx.pc.in index 76b4e39..1055601 100644 --- a/src/eixx.pc.in +++ b/src/eixx.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: @PACKAGE@ Description: EIXX: C++ Interface to Erlang -#Requires: boost_0_41_0 +#Requires: boost_1_55_0 Version: @PACKAGE_VERSION@ Libs: -L${libdir} @EI_LDFLAGS@ -leixx @EI_LIB@ @CRYPTO_LIBS@ Cflags: -I${includedir} @EI_CPPFLAGS@ From f586b9c97e11b0b3e297b9dc7813be66de4a72ce Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 14 Apr 2014 21:42:56 -0400 Subject: [PATCH 022/185] Added printout of LDFLAGS --- configure.ac | 1 + include/eixx/config.h | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index c25c3f5..bf9aa75 100644 --- a/configure.ac +++ b/configure.ac @@ -164,6 +164,7 @@ AC_OUTPUT echo echo "========================================================================" echo " CXXFLAGS: ${CXXFLAGS}" $BOOST_CPPFLAGS +echo " LDFLAGS: ${LDFLAGS} ${EI_LDFLAGS}" echo " BOOST: $BOOST_ROOT" echo " Erlang: $ERLANG_ROOT_DIR" echo "------------------------------------------------------------------------" diff --git a/include/eixx/config.h b/include/eixx/config.h index dcbba69..8da5773 100644 --- a/include/eixx/config.h +++ b/include/eixx/config.h @@ -46,9 +46,7 @@ #endif /* Algorithm MD2 in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_MD2 -#define EIXX_CRYPTO_WITH_MD2 1 -#endif +/* #undef CRYPTO_WITH_MD2 */ /* Algorithm MD4 in openssl crypto library */ #ifndef EIXX_CRYPTO_WITH_MD4 From 942f1ab404264744c7d8f0887634b51ed6b2db68 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 8 May 2014 08:23:45 -0400 Subject: [PATCH 023/185] Placement of basic_rpc_server to correct location --- configure.ac | 5 +- include/eixx/config.h | 291 ------------------ .../connect/transport_otp_connection_tcp.hpp | 2 +- src/Makefile.am | 5 +- 4 files changed, 5 insertions(+), 298 deletions(-) delete mode 100644 include/eixx/config.h diff --git a/configure.ac b/configure.ac index bf9aa75..2177f8f 100644 --- a/configure.ac +++ b/configure.ac @@ -5,8 +5,7 @@ AC_INIT([eixx], [1.1], [BUG-REPORT-ADDRESS]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux]) AM_INIT_AUTOMAKE([foreign -Wall -Wno-portability]) -AM_CONFIG_HEADER(config.h) -AX_PREFIX_CONFIG_H(include/eixx/config.h) +AC_CONFIG_HEADERS(config.h) AC_SUBST([eixxdir], [$libdir]) @@ -59,8 +58,6 @@ LT_INIT([disable-static]) AC_PROG_CXX AC_PROG_SED -#AC_CONFIG_HEADERS([config.h]) - # Checks for libraries. AX_BOOST_BASE([1.49.0], [], [AC_MSG_ERROR("BOOST library version >= 1.49.0 not found!")]) diff --git a/include/eixx/config.h b/include/eixx/config.h deleted file mode 100644 index 8da5773..0000000 --- a/include/eixx/config.h +++ /dev/null @@ -1,291 +0,0 @@ -#ifndef _INCLUDE_EIXX_CONFIG_H -#define _INCLUDE_EIXX_CONFIG_H 1 - -/* include/eixx/config.h. Generated automatically at end of configure. */ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Algorithm AES in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_AES -#define EIXX_CRYPTO_WITH_AES 1 -#endif - -/* Algorithm BF in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_BF -#define EIXX_CRYPTO_WITH_BF 1 -#endif - -/* Algorithm CAMELLIA in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_CAMELLIA -#define EIXX_CRYPTO_WITH_CAMELLIA 1 -#endif - -/* Algorithm CAST in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_CAST -#define EIXX_CRYPTO_WITH_CAST 1 -#endif - -/* Algorithm DES in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_DES -#define EIXX_CRYPTO_WITH_DES 1 -#endif - -/* Algorithm DH in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_DH -#define EIXX_CRYPTO_WITH_DH 1 -#endif - -/* Algorithm DSA in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_DSA -#define EIXX_CRYPTO_WITH_DSA 1 -#endif - -/* Algorithm IDEA in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_IDEA -#define EIXX_CRYPTO_WITH_IDEA 1 -#endif - -/* Algorithm MD2 in openssl crypto library */ -/* #undef CRYPTO_WITH_MD2 */ - -/* Algorithm MD4 in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_MD4 -#define EIXX_CRYPTO_WITH_MD4 1 -#endif - -/* Algorithm MD5 in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_MD5 -#define EIXX_CRYPTO_WITH_MD5 1 -#endif - -/* Algorithm RC2 in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_RC2 -#define EIXX_CRYPTO_WITH_RC2 1 -#endif - -/* Algorithm RC5 in openssl crypto library */ -/* #undef CRYPTO_WITH_RC5 */ - -/* Algorithm RIPEMD in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_RIPEMD -#define EIXX_CRYPTO_WITH_RIPEMD 1 -#endif - -/* Algorithm RSA in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_RSA -#define EIXX_CRYPTO_WITH_RSA 1 -#endif - -/* Algorithm SHA in openssl crypto library */ -#ifndef EIXX_CRYPTO_WITH_SHA -#define EIXX_CRYPTO_WITH_SHA 1 -#endif - -/* define if the Boost library is available */ -#ifndef EIXX_HAVE_BOOST -#define EIXX_HAVE_BOOST /**/ -#endif - -/* define if the Boost::ASIO library is available */ -#ifndef EIXX_HAVE_BOOST_ASIO -#define EIXX_HAVE_BOOST_ASIO /**/ -#endif - -/* define if the Boost::Date_Time library is available */ -#ifndef EIXX_HAVE_BOOST_DATE_TIME -#define EIXX_HAVE_BOOST_DATE_TIME /**/ -#endif - -/* define if the Boost::System library is available */ -#ifndef EIXX_HAVE_BOOST_SYSTEM -#define EIXX_HAVE_BOOST_SYSTEM /**/ -#endif - -/* define if the Boost::Thread library is available */ -#ifndef EIXX_HAVE_BOOST_THREAD -#define EIXX_HAVE_BOOST_THREAD /**/ -#endif - -/* define if the Boost::Unit_Test_Framework library is available */ -#ifndef EIXX_HAVE_BOOST_UNIT_TEST_FRAMEWORK -#define EIXX_HAVE_BOOST_UNIT_TEST_FRAMEWORK /**/ -#endif - -/* Openssl crypto library is available */ -#ifndef EIXX_HAVE_CRYPTO -#define EIXX_HAVE_CRYPTO 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_DLFCN_H -#define EIXX_HAVE_DLFCN_H 1 -#endif - -/* erl_interface/src/epmd/ei_epmd.h is available */ -#ifndef EIXX_HAVE_EI_EPMD -#define EIXX_HAVE_EI_EPMD 1 -#endif - -/* Define to 1 if you have the `gettimeofday' function. */ -#ifndef EIXX_HAVE_GETTIMEOFDAY -#define EIXX_HAVE_GETTIMEOFDAY 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_INTTYPES_H -#define EIXX_HAVE_INTTYPES_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_MEMORY_H -#define EIXX_HAVE_MEMORY_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_OPENSSL_MD5_H -#define EIXX_HAVE_OPENSSL_MD5_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_OPENSSL_OPENSSLCONF_H -#define EIXX_HAVE_OPENSSL_OPENSSLCONF_H 1 -#endif - -/* Define to 1 if you have the `socket' function. */ -#ifndef EIXX_HAVE_SOCKET -#define EIXX_HAVE_SOCKET 1 -#endif - -/* Define to 1 if you have the `sqrt' function. */ -/* #undef HAVE_SQRT */ - -/* Define to 1 if stdbool.h conforms to C99. */ -#ifndef EIXX_HAVE_STDBOOL_H -#define EIXX_HAVE_STDBOOL_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_STDINT_H -#define EIXX_HAVE_STDINT_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_STDLIB_H -#define EIXX_HAVE_STDLIB_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_STRINGS_H -#define EIXX_HAVE_STRINGS_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_STRING_H -#define EIXX_HAVE_STRING_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_SYS_STAT_H -#define EIXX_HAVE_SYS_STAT_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_SYS_TIME_H -#define EIXX_HAVE_SYS_TIME_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_SYS_TYPES_H -#define EIXX_HAVE_SYS_TYPES_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef EIXX_HAVE_UNISTD_H -#define EIXX_HAVE_UNISTD_H 1 -#endif - -/* Define to 1 if the system has the type `_Bool'. */ -#ifndef EIXX_HAVE__BOOL -#define EIXX_HAVE__BOOL 1 -#endif - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#ifndef EIXX_LT_OBJDIR -#define EIXX_LT_OBJDIR ".libs/" -#endif - -/* Name of package */ -#ifndef EIXX_PACKAGE -#define EIXX_PACKAGE "eixx" -#endif - -/* Define to the address where bug reports for this package should be sent. */ -#ifndef EIXX_PACKAGE_BUGREPORT -#define EIXX_PACKAGE_BUGREPORT "BUG-REPORT-ADDRESS" -#endif - -/* Define to the full name of this package. */ -#ifndef EIXX_PACKAGE_NAME -#define EIXX_PACKAGE_NAME "eixx" -#endif - -/* Define to the full name and version of this package. */ -#ifndef EIXX_PACKAGE_STRING -#define EIXX_PACKAGE_STRING "eixx 1.1" -#endif - -/* Define to the one symbol short name of this package. */ -#ifndef EIXX_PACKAGE_TARNAME -#define EIXX_PACKAGE_TARNAME "eixx" -#endif - -/* Define to the home page for this package. */ -#ifndef EIXX_PACKAGE_URL -#define EIXX_PACKAGE_URL "" -#endif - -/* Define to the version of this package. */ -#ifndef EIXX_PACKAGE_VERSION -#define EIXX_PACKAGE_VERSION "1.1" -#endif - -/* Define to 1 if you have the ANSI C header files. */ -#ifndef EIXX_STDC_HEADERS -#define EIXX_STDC_HEADERS 1 -#endif - -/* Version number of package */ -#ifndef EIXX_VERSION -#define EIXX_VERSION "1.1" -#endif - -/* Define for Solaris 2.5.1 so the uint32_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT32_T */ - -/* Define for Solaris 2.5.1 so the uint64_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT64_T */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* Define to the type of an unsigned integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint32_t */ - -/* Define to the type of an unsigned integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint64_t */ - -/* once: _INCLUDE_EIXX_CONFIG_H */ -#endif diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 24e7637..2fa2a3c 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #ifdef HAVE_CONFIG_H -#include +#include #endif #ifdef EIXX_HAVE_EI_EPMD diff --git a/src/Makefile.am b/src/Makefile.am index f9d429a..8a46f03 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,7 +8,6 @@ eixx_hdrs1 = alloc_pool.hpp \ alloc_pool_st.hpp \ alloc_std_debug.hpp \ alloc_std.hpp \ - config.h \ connect.hpp \ eixx.hpp \ eterm.hpp \ @@ -22,7 +21,6 @@ eixx_hdrs2 = connect/basic_otp_connection.hpp \ connect/basic_otp_node.hpp \ connect/basic_otp_node.ipp \ connect/basic_otp_node_local.hpp \ - connect/detail/basic_rpc_server.hpp \ connect/test_helper.hpp \ connect/transport_msg.hpp \ connect/transport_otp_connection.hpp \ @@ -72,6 +70,7 @@ eixx_hdrs4 = util/async_queue.hpp \ util/string_util.hpp \ util/sync.hpp \ util/timeout.hpp +eixx_hdrs5 = connect/detail/basic_rpc_server.hpp eixx_headers= $(eixx_hdrs1) \ $(eixx_hdrs2) \ @@ -86,6 +85,8 @@ libeixx_la_hdr3dir = $(includedir)/@PACKAGE@/marshal libeixx_la_hdr3_HEADERS = $(eixx_hdrs3:%=../include/@PACKAGE@/%) libeixx_la_hdr4dir = $(includedir)/@PACKAGE@/util libeixx_la_hdr4_HEADERS = $(eixx_hdrs4:%=../include/@PACKAGE@/%) +libeixx_la_hdr5dir = $(includedir)/@PACKAGE@/connect/detail +libeixx_la_hdr5_HEADERS = $(eixx_hdrs5:%=../include/@PACKAGE@/%) libeixx_la_SOURCES = am.cpp atom.cpp defaults.cpp ref.cpp \ basic_otp_node_local.cpp \ From e411b8458d456c01ea0f1c1ec9787589a41c440e Mon Sep 17 00:00:00 2001 From: Dmitriy Kargapolov Date: Thu, 8 May 2014 12:08:34 -0400 Subject: [PATCH 024/185] switching back to prefixed config.h, making it installable --- .gitignore | 3 ++- configure.ac | 1 + include/eixx/connect/transport_otp_connection_tcp.hpp | 4 +--- include/eixx/util/common.hpp | 4 +--- src/Makefile.am | 11 ++++++----- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 55dade6..3e0f15d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,8 @@ build-aux/ltversion.m4 build-aux/lt~obsolete.m4 build-aux/missing _configs.sed -/config.h +config.h +include/eixx/config.h config.h.in* config.log config.status diff --git a/configure.ac b/configure.ac index 2177f8f..3b5f2c6 100644 --- a/configure.ac +++ b/configure.ac @@ -6,6 +6,7 @@ AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux]) AM_INIT_AUTOMAKE([foreign -Wall -Wno-portability]) AC_CONFIG_HEADERS(config.h) +AX_PREFIX_CONFIG_H(include/eixx/config.h) AC_SUBST([eixxdir], [$libdir]) diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 2fa2a3c..69dbead 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -37,9 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -#ifdef HAVE_CONFIG_H -#include -#endif +#include #ifdef EIXX_HAVE_EI_EPMD extern "C" { diff --git a/include/eixx/util/common.hpp b/include/eixx/util/common.hpp index 9a94fc1..dc4e1a2 100644 --- a/include/eixx/util/common.hpp +++ b/include/eixx/util/common.hpp @@ -21,9 +21,7 @@ #include #include -#ifdef HAVE_CONFIG_H -# include -#endif +#include #define ERL_MONITOR_P 19 #define ERL_DEMONITOR_P 20 diff --git a/src/Makefile.am b/src/Makefile.am index 8a46f03..1d0c92f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,11 +8,12 @@ eixx_hdrs1 = alloc_pool.hpp \ alloc_pool_st.hpp \ alloc_std_debug.hpp \ alloc_std.hpp \ + config.h \ connect.hpp \ eixx.hpp \ eterm.hpp \ - eterm_exception.hpp \ - namespace.hpp + eterm_exception.hpp \ + namespace.hpp eixx_hdrs2 = connect/basic_otp_connection.hpp \ connect/basic_otp_mailbox.hpp \ connect/basic_otp_mailbox.ipp \ @@ -62,10 +63,10 @@ eixx_hdrs3 = marshal/alloc_base.hpp \ marshal/visit_subst.hpp \ marshal/visit_to_string.hpp eixx_hdrs4 = util/async_queue.hpp \ - util/async_wait_timeout.hpp \ - util/atom_table.hpp \ + util/async_wait_timeout.hpp \ + util/atom_table.hpp \ util/common.hpp \ - util/compiler_hints.hpp \ + util/compiler_hints.hpp \ util/hashtable.hpp \ util/string_util.hpp \ util/sync.hpp \ From 6a2682777ad133697d257e5dd5b68af6df2f91ef Mon Sep 17 00:00:00 2001 From: Dmitriy Kargapolov Date: Fri, 9 May 2014 21:16:30 -0400 Subject: [PATCH 025/185] eixx::eterm::encode() fix --- include/eixx/marshal/eterm.ipp | 2 +- include/eixx/marshal/string.hpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/eixx/marshal/eterm.ipp b/include/eixx/marshal/eterm.ipp index 91be35d..fdcd0b2 100644 --- a/include/eixx/marshal/eterm.ipp +++ b/include/eixx/marshal/eterm.ipp @@ -205,7 +205,7 @@ template string eterm::encode(size_t a_header_size, bool a_with_version) const { size_t size = encode_size(a_header_size, a_with_version); - string out("", size); + string out(NULL, size); char* p = const_cast(out.c_str()); encode(p, size, a_header_size, a_with_version); return out; diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index 36ab794..a742d1a 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -87,8 +87,11 @@ class string return; } m_blob = new blob(n+1, a); - memcpy(m_blob->data(), s, m_blob->size()); - m_blob->data()[m_blob->size()-1] = '\0'; + if (s != NULL) { + memcpy(m_blob->data(), s, m_blob->size()); + m_blob->data()[m_blob->size()-1] = '\0'; + } else + m_blob->data()[0] = '\0'; } string(const string& s) : m_blob(s.m_blob) { if (m_blob) m_blob->inc_rc(); From d646cd20640a94ec8426279bc8df60217529c59b Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Sep 2014 08:50:48 -0400 Subject: [PATCH 026/185] Added subst() function --- configure.ac | 18 +++++++++++++++++- include/eixx/marshal/eterm.hpp | 14 ++++++++++++++ include/eixx/marshal/eterm.ipp | 21 +++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 2177f8f..edf8bbb 100644 --- a/configure.ac +++ b/configure.ac @@ -51,6 +51,20 @@ AC_ARG_ENABLE(warnings, ], ) +AC_LANG_PUSH(C++) +AC_ARG_ENABLE(cxx11, + AC_HELP_STRING([--disable-cxx11],[disable c++11 standard [default=no]]), + [ if test "x${enable_cxx11}" != "xno" -a -z "${disable_cxx11}"; then + AX_CXX_COMPILE_STDCXX_11([noext], [optional]) + fi + ], + [ + AX_CXX_COMPILE_STDCXX_11([noext], [optional]) + ] +) + +AC_LANG_POP([C++]) + # libtool LT_INIT([disable-static]) @@ -62,9 +76,11 @@ AC_PROG_SED AX_BOOST_BASE([1.49.0], [], [AC_MSG_ERROR("BOOST library version >= 1.49.0 not found!")]) AX_BOOST_SYSTEM -AX_BOOST_THREAD AX_BOOST_ASIO AX_BOOST_DATE_TIME +# workaround unexpected extra dependency on boost_system library (at least in 1.49) +LDFLAGS+=" $BOOST_LDFLAGS $BOOST_SYSTEM_LIB" +AX_BOOST_THREAD AX_BOOST_UNIT_TEST_FRAMEWORK # eixx requires md5 support diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 78eee45..068cda4 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -302,9 +302,11 @@ class eterm { /** * Move constructor */ +#if __cplusplus >= 201103L eterm(eterm&& a) { replace(&a); } +#endif /** * Destruct this term. For compound terms it decreases the @@ -341,6 +343,7 @@ class eterm { * Assign the value to this term. If current term has been initialized, * its old value is destructed. */ +#if __cplusplus >= 201103L eterm& operator= (eterm&& a) { if (this != &a) { if (m_type >= STRING) @@ -349,6 +352,7 @@ class eterm { } return *this; } +#endif template void set(const T& a) { @@ -466,6 +470,16 @@ class eterm { bool subst(eterm& out, const varbind* binding) const throw (err_invalid_term, err_unbound_variable); + /** Substitutes all variables in the term \a a. */ + eterm subst(const eterm& a, const varbind& binding) const + throw (err_invalid_term, err_unbound_variable); + +#if __cplusplus >= 201103L + /** Substitutes all variables in the term \a a. */ + eterm subst(eterm&& a, const varbind& binding) const + throw (err_invalid_term, err_unbound_variable); +#endif + /** * This method finds the first unbound variable in a term for * the given variable binding. It can be used to check if the term has diff --git a/include/eixx/marshal/eterm.ipp b/include/eixx/marshal/eterm.ipp index 91be35d..c225e59 100644 --- a/include/eixx/marshal/eterm.ipp +++ b/include/eixx/marshal/eterm.ipp @@ -279,6 +279,27 @@ bool eterm::subst(eterm& out, const varbind* binding) const return visitor.apply_visitor(*this); } +template +eterm eterm::subst(const eterm& a, const varbind& binding) const + throw (err_invalid_term, err_unbound_variable) { + eterm out(a); + visit_eterm_subst visitor(out, binding); + static const eterm s_null; + return visitor.apply_visitor(*this) ? out : s_null; +} + +#if __cplusplus >= 201103L + +template +eterm eterm::subst(eterm&& a, const varbind& binding) const + throw (err_invalid_term, err_unbound_variable) { + visit_eterm_subst visitor(a, binding); + static const eterm s_null; + return visitor.apply_visitor(*this) ? std::move(a) : s_null; +} + +#endif + template eterm eterm::format(const Alloc& a_alloc, const char** fmt, va_list* pap) throw (err_format_exception) From 10ccffcf44c59f259fbc73ac574443ce69e37cb5 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Sep 2014 12:39:12 -0400 Subject: [PATCH 027/185] Added varbind initializer list --- include/eixx/marshal/eterm.hpp | 8 +----- include/eixx/marshal/eterm.ipp | 24 +++++----------- include/eixx/marshal/varbind.hpp | 32 +++++++++++++++++++++ src/Makefile.am | 24 ++++++++-------- test/Makefile.am | 49 ++++++++++++++++---------------- test/test_eterm.cpp | 20 +++++++++++++ 6 files changed, 97 insertions(+), 60 deletions(-) diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 068cda4..9f88e11 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -471,15 +471,9 @@ class eterm { throw (err_invalid_term, err_unbound_variable); /** Substitutes all variables in the term \a a. */ - eterm subst(const eterm& a, const varbind& binding) const + eterm apply(const varbind& binding) const throw (err_invalid_term, err_unbound_variable); -#if __cplusplus >= 201103L - /** Substitutes all variables in the term \a a. */ - eterm subst(eterm&& a, const varbind& binding) const - throw (err_invalid_term, err_unbound_variable); -#endif - /** * This method finds the first unbound variable in a term for * the given variable binding. It can be used to check if the term has diff --git a/include/eixx/marshal/eterm.ipp b/include/eixx/marshal/eterm.ipp index 1ccd3ca..b910f06 100644 --- a/include/eixx/marshal/eterm.ipp +++ b/include/eixx/marshal/eterm.ipp @@ -274,32 +274,22 @@ bool eterm::match( template bool eterm::subst(eterm& out, const varbind* binding) const - throw (err_invalid_term, err_unbound_variable) { + throw (err_invalid_term, err_unbound_variable) +{ visit_eterm_subst visitor(out, binding); return visitor.apply_visitor(*this); } template -eterm eterm::subst(const eterm& a, const varbind& binding) const - throw (err_invalid_term, err_unbound_variable) { - eterm out(a); - visit_eterm_subst visitor(out, binding); +eterm eterm::apply(const varbind& binding) const + throw (err_invalid_term, err_unbound_variable) +{ + eterm out; + visit_eterm_subst visitor(out, &binding); static const eterm s_null; return visitor.apply_visitor(*this) ? out : s_null; } -#if __cplusplus >= 201103L - -template -eterm eterm::subst(eterm&& a, const varbind& binding) const - throw (err_invalid_term, err_unbound_variable) { - visit_eterm_subst visitor(a, binding); - static const eterm s_null; - return visitor.apply_visitor(*this) ? std::move(a) : s_null; -} - -#endif - template eterm eterm::format(const Alloc& a_alloc, const char** fmt, va_list* pap) throw (err_format_exception) diff --git a/include/eixx/marshal/varbind.hpp b/include/eixx/marshal/varbind.hpp index 39b542d..cd057ab 100644 --- a/include/eixx/marshal/varbind.hpp +++ b/include/eixx/marshal/varbind.hpp @@ -41,6 +41,29 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace EIXX_NAMESPACE { namespace marshal { +/// Name-value pair associating an eterm with an atom name +template +struct epair : std::pair > { + typedef std::pair > base; + + epair(atom a_name, const eterm& a_value) : base(a_name, a_value) {} + +#if __cplusplus >= 201103L + epair(atom a_name, eterm&& a_value) : base(a_name, std::move(a_value)) {} + epair(const epair& a_rhs) : base(a_rhs) {} + epair(epair&& a_rhs) : base(std::forward(a_rhs)) {} + + epair& operator=(const epair& a_rhs) { + return base::operator=(static_cast(a_rhs)); + } + +#endif + + atom name() const { return base::first; } + const eterm& value() const { return base::second; } + eterm& value() { return base::second; } +}; + /** * This class maintains bindings of variables to values. */ @@ -62,6 +85,15 @@ class varbind { varbind(const varbind& rhs) : m_term_map(rhs.m_term_map) {} +#if __cplusplus >= 201103L + varbind(std::initializer_list> a_list) { + m_term_map.insert(a_list.begin(), a_list.end()); + } +// varbind(std::initializer_list> a_list) { +// m_term_map.insert(a_list.begin(), a_list.end()); +// } +#endif + void copy(const varbind& rhs) { m_term_map = rhs.m_term_map; } /** diff --git a/src/Makefile.am b/src/Makefile.am index 1d0c92f..3561bb6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,13 +70,13 @@ eixx_hdrs4 = util/async_queue.hpp \ util/hashtable.hpp \ util/string_util.hpp \ util/sync.hpp \ - util/timeout.hpp + util/timeout.hpp eixx_hdrs5 = connect/detail/basic_rpc_server.hpp eixx_headers= $(eixx_hdrs1) \ - $(eixx_hdrs2) \ - $(eixx_hdrs3) \ - $(eixx_hdrs4) + $(eixx_hdrs2) \ + $(eixx_hdrs3) \ + $(eixx_hdrs4) libeixx_la_hdr1dir = $(includedir)/@PACKAGE@ libeixx_la_hdr1_HEADERS = $(eixx_hdrs1:%=../include/@PACKAGE@/%) @@ -90,19 +90,19 @@ libeixx_la_hdr5dir = $(includedir)/@PACKAGE@/connect/detail libeixx_la_hdr5_HEADERS = $(eixx_hdrs5:%=../include/@PACKAGE@/%) libeixx_la_SOURCES = am.cpp atom.cpp defaults.cpp ref.cpp \ - basic_otp_node_local.cpp \ - $(eixx_headers:%=../include/@PACKAGE@/%) + basic_otp_node_local.cpp \ + $(eixx_headers:%=../include/@PACKAGE@/%) libeixx_la_LTADD = -version-info 1:1:0 -shared libeixx_la_LIBS = $(BOOST_THREAD_LIB) $(CRYPTO_LIBS) libeixx_la_CXXFLAGS = $(if $(tr1),-std=c++0x) \ - -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ - -I../include $(BOOST_CPPFLAGS) \ - $(EI_CPPFLAGS) + -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ + -I../include $(BOOST_CPPFLAGS) \ + $(EI_CPPFLAGS) #EXTRA_DIST = ../README overview.inl overview_usage.inl overview_config.inl test_node_SOURCES = test_node.cpp test_node_CPPFLAGS = -g -O0 -I$(srcdir)/../include $(BOOST_CPPFLAGS) $(EI_CPPFLAGS) -test_node_LDFLAGS = $(BOOST_LDFLAGS) $(EI_LDFLAGS) -test_node_LDADD = libeixx.la $(EI_LIB) \ - $(BOOST_SYSTEM_LIB) $(BOOST_THREAD_LIB) $(CRYPTO_LIBS) +test_node_LDFLAGS = $(BOOST_LDFLAGS) $(EI_LDFLAGS) +test_node_LIBS = libeixx.la $(EI_LIB) \ + $(BOOST_SYSTEM_LIB) $(BOOST_THREAD_LIB) $(CRYPTO_LIBS) \ No newline at end of file diff --git a/test/Makefile.am b/test/Makefile.am index c0884d2..1c0b348 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,32 +1,33 @@ bin_PROGRAMS = test_eterm test_perf test_connect AM_CXXFLAGS = -I. -I$(srcdir)/../include $(BOOST_CPPFLAGS) \ - -I$(ERLANG_LIB_DIR_erl_interface)/include \ - -I$(ERLANG_LIB_DIR_erl_interface)/src + -I$(ERLANG_LIB_DIR_erl_interface)/include \ + -I$(ERLANG_LIB_DIR_erl_interface)/src +AM_LDFLAGS = -W,l -rpath -W,l$(subst -L,,$(BOOST_LDFLAGS)) -test_eterm_SOURCES = test_eterm.cpp test_eterm_encode.cpp \ - test_eterm_format.cpp test_eterm_match.cpp \ - test_eterm_pool.cpp test_eterm_refc.cpp \ - test_mailbox.cpp test_node.cpp -test_eterm_CPPFLAGS = -DBOOST_TEST_DYN_LINK -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ - $(if $(debug),-DEIXX_DEBUG) -test_eterm_LDFLAGS = $(BOOST_LDFLAGS) \ - -L$(ERLANG_LIB_DIR_erl_interface)/lib -test_eterm_LDADD = -L../src/.libs -leixx -lei \ - $(BOOST_SYSTEM_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) \ - $(BOOST_THREAD_LIB) +test_eterm_SOURCES = test_eterm.cpp test_eterm_encode.cpp \ + test_eterm_format.cpp test_eterm_match.cpp \ + test_eterm_pool.cpp test_eterm_refc.cpp \ + test_mailbox.cpp test_node.cpp +test_eterm_CPPFLAGS = -DBOOST_TEST_DYN_LINK -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ + $(if $(debug),-DEIXX_DEBUG) +test_eterm_LDFLAGS = $(BOOST_LDFLAGS) \ + -L$(ERLANG_LIB_DIR_erl_interface)/lib +test_eterm_LDADD = -L../src/.libs -leixx -lei \ + $(BOOST_SYSTEM_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) \ + $(BOOST_THREAD_LIB) -test_connect_SOURCES = test_async_queue.cpp -test_connect_CPPFLAGS = -DBOOST_TEST_DYN_LINK -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ - $(if $(debug),-DEIXX_DEBUG) -test_connect_LDFLAGS = $(BOOST_LDFLAGS) -test_connect_LDADD = -L../src/.libs -leixx \ - $(BOOST_SYSTEM_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) \ - $(BOOST_THREAD_LIB) +test_connect_SOURCES = test_async_queue.cpp +test_connect_CPPFLAGS = -DBOOST_TEST_DYN_LINK -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ + $(if $(debug),-DEIXX_DEBUG) +test_connect_LDFLAGS = $(BOOST_LDFLAGS) +test_connect_LDADD = -L../src/.libs -leixx \ + $(BOOST_SYSTEM_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) \ + $(BOOST_THREAD_LIB) -test_perf_SOURCES = test_perf.cpp -test_perf_CPPFLAGS = -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) -test_perf_LDFLAGS = -L$(ERLANG_LIB_DIR_erl_interface)/lib $(BOOST_LDFLAGS) -test_perf_LDADD = -L../src/.libs -leixx $(BOOST_SYSTEM_LIB) +test_perf_SOURCES = test_perf.cpp +test_perf_CPPFLAGS = -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) +test_perf_LDFLAGS = -L$(ERLANG_LIB_DIR_erl_interface)/lib $(BOOST_LDFLAGS) +test_perf_LDADD = -L../src/.libs -leixx $(BOOST_SYSTEM_LIB) diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 10e9d80..fe42fde 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -617,6 +617,26 @@ BOOST_AUTO_TEST_CASE( test_varbind ) binding1.merge(binding2); BOOST_REQUIRE_EQUAL(3ul, binding1.count()); + +#if __cplusplus >= 201103L + atom am_a("A"); + atom am_b("B"); + atom am_c("C"); + varbind binding3{ {atom(am_a), 10}, {am_b, 200.0}, {"C", "abc"} }; + BOOST_CHECK_EQUAL(3u, binding3.count()); + + BOOST_CHECK_EQUAL(10, binding3[am_a]->to_long()); + BOOST_CHECK_EQUAL(200.0, binding3[am_b]->to_double()); + BOOST_CHECK_EQUAL("abc", binding3[am_c]->to_str()); + + eterm term = eterm::format("{ok, A::int(), B::float(), C::string()}"); + eterm got0 = eterm::format("{ok, 10, 200.0, \"abc\"}"); + eterm got1 = term.apply({{atom(am_a), 10}, {am_b, 200.0}, {"C", "abc"}}); + eterm got2 = term.apply(binding3); + + BOOST_CHECK(got0 == got1); + BOOST_CHECK(got0 == got2); +#endif } eterm f() { From 17dd3f0e5f90b9df4d8c1d5a9444b5c996f682c0 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Sep 2014 12:41:24 -0400 Subject: [PATCH 028/185] Added varbind initializer list --- test/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Makefile.am b/test/Makefile.am index 1c0b348..6a5e77a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -3,7 +3,6 @@ bin_PROGRAMS = test_eterm test_perf test_connect AM_CXXFLAGS = -I. -I$(srcdir)/../include $(BOOST_CPPFLAGS) \ -I$(ERLANG_LIB_DIR_erl_interface)/include \ -I$(ERLANG_LIB_DIR_erl_interface)/src -AM_LDFLAGS = -W,l -rpath -W,l$(subst -L,,$(BOOST_LDFLAGS)) test_eterm_SOURCES = test_eterm.cpp test_eterm_encode.cpp \ test_eterm_format.cpp test_eterm_match.cpp \ From f4763f5e7ef539d6613086adf9c9a500e2ae5d99 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Sep 2014 13:10:54 -0400 Subject: [PATCH 029/185] Makefile reverted --- src/Makefile.am | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 3561bb6..1d0c92f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,13 +70,13 @@ eixx_hdrs4 = util/async_queue.hpp \ util/hashtable.hpp \ util/string_util.hpp \ util/sync.hpp \ - util/timeout.hpp + util/timeout.hpp eixx_hdrs5 = connect/detail/basic_rpc_server.hpp eixx_headers= $(eixx_hdrs1) \ - $(eixx_hdrs2) \ - $(eixx_hdrs3) \ - $(eixx_hdrs4) + $(eixx_hdrs2) \ + $(eixx_hdrs3) \ + $(eixx_hdrs4) libeixx_la_hdr1dir = $(includedir)/@PACKAGE@ libeixx_la_hdr1_HEADERS = $(eixx_hdrs1:%=../include/@PACKAGE@/%) @@ -90,19 +90,19 @@ libeixx_la_hdr5dir = $(includedir)/@PACKAGE@/connect/detail libeixx_la_hdr5_HEADERS = $(eixx_hdrs5:%=../include/@PACKAGE@/%) libeixx_la_SOURCES = am.cpp atom.cpp defaults.cpp ref.cpp \ - basic_otp_node_local.cpp \ - $(eixx_headers:%=../include/@PACKAGE@/%) + basic_otp_node_local.cpp \ + $(eixx_headers:%=../include/@PACKAGE@/%) libeixx_la_LTADD = -version-info 1:1:0 -shared libeixx_la_LIBS = $(BOOST_THREAD_LIB) $(CRYPTO_LIBS) libeixx_la_CXXFLAGS = $(if $(tr1),-std=c++0x) \ - -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ - -I../include $(BOOST_CPPFLAGS) \ - $(EI_CPPFLAGS) + -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ + -I../include $(BOOST_CPPFLAGS) \ + $(EI_CPPFLAGS) #EXTRA_DIST = ../README overview.inl overview_usage.inl overview_config.inl test_node_SOURCES = test_node.cpp test_node_CPPFLAGS = -g -O0 -I$(srcdir)/../include $(BOOST_CPPFLAGS) $(EI_CPPFLAGS) -test_node_LDFLAGS = $(BOOST_LDFLAGS) $(EI_LDFLAGS) -test_node_LIBS = libeixx.la $(EI_LIB) \ - $(BOOST_SYSTEM_LIB) $(BOOST_THREAD_LIB) $(CRYPTO_LIBS) \ No newline at end of file +test_node_LDFLAGS = $(BOOST_LDFLAGS) $(EI_LDFLAGS) +test_node_LDADD = libeixx.la $(EI_LIB) \ + $(BOOST_SYSTEM_LIB) $(BOOST_THREAD_LIB) $(CRYPTO_LIBS) From bae1af18f9390efc556306e031147fd0c1dd2b98 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Sep 2014 13:40:28 -0400 Subject: [PATCH 030/185] Test adjusted --- test/test_eterm.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index fe42fde..a079c51 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -622,7 +622,8 @@ BOOST_AUTO_TEST_CASE( test_varbind ) atom am_a("A"); atom am_b("B"); atom am_c("C"); - varbind binding3{ {atom(am_a), 10}, {am_b, 200.0}, {"C", "abc"} }; + + varbind binding3{ {am_a, 10}, {am_b, 200.0}, {"C", "abc"} }; BOOST_CHECK_EQUAL(3u, binding3.count()); BOOST_CHECK_EQUAL(10, binding3[am_a]->to_long()); @@ -631,11 +632,13 @@ BOOST_AUTO_TEST_CASE( test_varbind ) eterm term = eterm::format("{ok, A::int(), B::float(), C::string()}"); eterm got0 = eterm::format("{ok, 10, 200.0, \"abc\"}"); - eterm got1 = term.apply({{atom(am_a), 10}, {am_b, 200.0}, {"C", "abc"}}); - eterm got2 = term.apply(binding3); + eterm got1 = term.apply({{am_a, 10}, {am_b, 200.0}, {"C", "abc"}}); + eterm got2 = term.apply({{am_a, 10}, {am_b, 200.0}, {am_c, "abc"}}); + eterm got3 = term.apply(binding3); BOOST_CHECK(got0 == got1); BOOST_CHECK(got0 == got2); + BOOST_CHECK(got0 == got3); #endif } From ee90bd4fb1fc21848ab29771755c004df49b8d9d Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Sep 2014 15:24:00 -0400 Subject: [PATCH 031/185] Added rpath --- src/eixx.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eixx.pc.in b/src/eixx.pc.in index 1055601..055f372 100644 --- a/src/eixx.pc.in +++ b/src/eixx.pc.in @@ -7,6 +7,6 @@ Name: @PACKAGE@ Description: EIXX: C++ Interface to Erlang #Requires: boost_1_55_0 Version: @PACKAGE_VERSION@ -Libs: -L${libdir} @EI_LDFLAGS@ -leixx @EI_LIB@ @CRYPTO_LIBS@ +Libs: -L${libdir} @EI_LDFLAGS@ -Wl,-rpath,${libdir} -leixx @EI_LIB@ @CRYPTO_LIBS@ Cflags: -I${includedir} @EI_CPPFLAGS@ From 7e52873a27d9919d2d1015bc7d2927fccbf12df8 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Sep 2014 23:22:40 -0400 Subject: [PATCH 032/185] Var string to list matching of [] lists fixed --- include/eixx/marshal/list.ipp | 32 ++++++++++++++++---------------- include/eixx/marshal/var.hpp | 20 +++++++++++--------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/include/eixx/marshal/list.ipp b/include/eixx/marshal/list.ipp index f08f439..0d1a499 100644 --- a/include/eixx/marshal/list.ipp +++ b/include/eixx/marshal/list.ipp @@ -107,27 +107,27 @@ list::list(const char *buf, int& idx, size_t size, const Alloc& a_alloc) int arity; if (ei_decode_list_header(buf, &idx, &arity) < 0) err_decode_exception("Error decoding list header", idx); - m_blob = new blob_t(sizeof(header_t) + arity*sizeof(cons_t), a_alloc); - header_t* l_header = header(); - l_header->initialized = true; - l_header->alloc_size = arity; - l_header->size = arity; - - cons_t* hd = l_header->head; - for (cons_t* end = hd+arity; hd != end; ++hd) { - eterm et(buf, idx, size, a_alloc); - new (&hd->node) eterm(et); - hd->next = hd+1; - } - if (arity == 0) { - l_header->tail = NULL; - } else { + if (arity == 0) + m_blob = NULL; + else { + m_blob = new blob_t(sizeof(header_t) + arity*sizeof(cons_t), a_alloc); + header_t* l_header = header(); + l_header->initialized = true; + l_header->alloc_size = arity; + l_header->size = arity; + + cons_t* hd = l_header->head; + for (cons_t* end = hd+arity; hd != end; ++hd) { + eterm et(buf, idx, size, a_alloc); + new (&hd->node) eterm(et); + hd->next = hd+1; + } l_header->tail = hd-1; l_header->tail->next = NULL; if (*(buf+idx) != ERL_NIL_EXT) throw err_decode_exception("Not a NIL list!", idx); - idx++; } + idx++; BOOST_ASSERT((size_t)idx <= size); } diff --git a/include/eixx/marshal/var.hpp b/include/eixx/marshal/var.hpp index f6bb0c9..97ea7e1 100644 --- a/include/eixx/marshal/var.hpp +++ b/include/eixx/marshal/var.hpp @@ -51,11 +51,13 @@ namespace marshal { **/ class var { - atom m_name; - int m_type; + atom m_name; + eterm_type m_type; - bool check_type(eterm_type t) const { - return is_any() || m_type == UNDEFINED || t == m_type; + template + bool check_type(const eterm& t) const { + return is_any() || m_type == UNDEFINED || t.type() == m_type + || (m_type == STRING && t.is_list() && t.to_list().empty()); } eterm_type set(eterm_type t) { return m_name == am_ANY_ ? UNDEFINED : t; } @@ -76,7 +78,7 @@ class var atom name() const { return m_name; } size_t length() const { return m_name.length(); } - eterm_type type() const { return (eterm_type)m_type; } + eterm_type type() const { return m_type; } bool is_any() const { return name() == am_ANY_; } std::string to_string() const { @@ -105,7 +107,7 @@ class var throw (err_unbound_variable) { const eterm* term = binding ? binding->find(name()) : NULL; - if (!term || !check_type(term->type())) + if (!term || !check_type(*term)) throw err_unbound_variable(c_str()); out = *term; return true; @@ -119,8 +121,8 @@ class var if (!binding) return false; const eterm* value = binding->find(name()); if (value) - return check_type(value->type()) ? value->match(pattern, binding) : false; - if (!check_type(pattern.type())) + return check_type(*value) ? value->match(pattern, binding) : false; + if (!check_type(pattern)) return false; // Bind the variable eterm et; @@ -131,7 +133,7 @@ class var template std::ostream& dump(std::ostream& out, const varbind* binding = NULL) const { const eterm* term = binding ? binding->find(name()) : NULL; - return out << (term && check_type(term->type()) + return out << (term && check_type(*term) ? term->to_string(std::string::npos, binding) : to_string()); } }; From 6e2d415df8bdd0197198acd5c0e01974ea08bb3b Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Sep 2014 23:39:27 -0400 Subject: [PATCH 033/185] a --- TODO | 1 + include/eixx/marshal/list.ipp | 33 +++++++++++++++++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/TODO b/TODO index 2636748..8bffbaa 100644 --- a/TODO +++ b/TODO @@ -1,2 +1,3 @@ 1. Check serialization of long: -6478876429381754229 2. Check encoding binary encoding of: ["ecg",-6478876429381754229,Pid,"example_core",29633] +3. Optimize an empty list not to allocate space. See commit 7e52873a diff --git a/include/eixx/marshal/list.ipp b/include/eixx/marshal/list.ipp index 0d1a499..86da4bb 100644 --- a/include/eixx/marshal/list.ipp +++ b/include/eixx/marshal/list.ipp @@ -107,27 +107,28 @@ list::list(const char *buf, int& idx, size_t size, const Alloc& a_alloc) int arity; if (ei_decode_list_header(buf, &idx, &arity) < 0) err_decode_exception("Error decoding list header", idx); - if (arity == 0) - m_blob = NULL; - else { - m_blob = new blob_t(sizeof(header_t) + arity*sizeof(cons_t), a_alloc); - header_t* l_header = header(); - l_header->initialized = true; - l_header->alloc_size = arity; - l_header->size = arity; - - cons_t* hd = l_header->head; - for (cons_t* end = hd+arity; hd != end; ++hd) { - eterm et(buf, idx, size, a_alloc); - new (&hd->node) eterm(et); - hd->next = hd+1; - } +// TODO: optimize for an empty list!!! + m_blob = new blob_t(sizeof(header_t) + arity*sizeof(cons_t), a_alloc); + header_t* l_header = header(); + l_header->initialized = true; + l_header->alloc_size = arity; + l_header->size = arity; + + cons_t* hd = l_header->head; + for (cons_t* end = hd+arity; hd != end; ++hd) { + eterm et(buf, idx, size, a_alloc); + new (&hd->node) eterm(et); + hd->next = hd+1; + } + if (arity == 0) { + l_header->tail = NULL; + } else { l_header->tail = hd-1; l_header->tail->next = NULL; if (*(buf+idx) != ERL_NIL_EXT) throw err_decode_exception("Not a NIL list!", idx); + idx++; } - idx++; BOOST_ASSERT((size_t)idx <= size); } From 1a483f2260ee1293549dde8b719d299e45d2db17 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Fri, 17 Oct 2014 23:58:48 -0400 Subject: [PATCH 034/185] Clang compilation bugfix --- include/eixx/marshal/eterm_format.ipp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eixx/marshal/eterm_format.ipp b/include/eixx/marshal/eterm_format.ipp index 0f495ee..4aa223f 100644 --- a/include/eixx/marshal/eterm_format.ipp +++ b/include/eixx/marshal/eterm_format.ipp @@ -402,7 +402,7 @@ namespace marshal { template static void eformat(atom& mod, atom& fun, eterm& args, - const char** fmt, va_list* pap, const Alloc& a_alloc = Alloc()) + const char** fmt, va_list* pap, const Alloc& a_alloc) { Alloc alloc(a_alloc); vector v(alloc); From 7ee899af2f93e09f98cc16bbfa764c258dfe0896 Mon Sep 17 00:00:00 2001 From: erlanger Date: Fri, 7 Nov 2014 01:02:16 -0500 Subject: [PATCH 035/185] Allow header-only marshalling, no need for libeixx.so --- include/eixx/marshal/am.hpp | 2 +- include/eixx/marshal/atom.hpp | 11 +++- include/eixx/marshal/defaults.hpp | 38 +++++++++++ include/eixx/marshal/eterm.ipp | 59 +++++++++++++++++ include/eixx/marshal/pid.hpp | 2 +- include/eixx/marshal/port.hpp | 2 +- include/eixx/marshal/ref.hpp | 10 ++- src/Makefile.am | 2 +- src/am.cpp | 1 - src/atom.cpp | 40 ------------ src/defaults.cpp | 102 ------------------------------ src/ref.cpp | 33 ---------- 12 files changed, 117 insertions(+), 185 deletions(-) delete mode 100644 src/atom.cpp delete mode 100644 src/defaults.cpp delete mode 100644 src/ref.cpp diff --git a/include/eixx/marshal/am.hpp b/include/eixx/marshal/am.hpp index 79d4abc..02420ee 100644 --- a/include/eixx/marshal/am.hpp +++ b/include/eixx/marshal/am.hpp @@ -41,7 +41,7 @@ namespace EIXX_NAMESPACE { // Constant global atom values - extern const atom am_ANY_; + const atom am_ANY_ = atom("_"); extern const atom am_badrpc; extern const atom am_call; extern const atom am_cast; diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 73a9d08..149a8ba 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -72,10 +72,16 @@ class atom int m_index; public: - static util::atom_table& atom_table(); + inline static util::atom_table& atom_table() { + static util::atom_table s_atom_table; + return s_atom_table; + } /// Returns empty atom - static const atom null; + inline static const atom null() { + static const atom null = atom(); + return null; + } /// Create an empty atom atom() : m_index(0) { @@ -202,6 +208,7 @@ inline atom make_node_name(const std::string& s) return atom(s); } + } // namespace marshal } // namespace EIXX_NAMESPACE diff --git a/include/eixx/marshal/defaults.hpp b/include/eixx/marshal/defaults.hpp index 1fc578a..52ef2c8 100644 --- a/include/eixx/marshal/defaults.hpp +++ b/include/eixx/marshal/defaults.hpp @@ -96,6 +96,44 @@ namespace EIXX_NAMESPACE { return type_string_to_type(s, strlen(s)); } + inline const char* type_to_string(eterm_type a_type) { + switch (a_type) { + case LONG : return "LONG"; + case DOUBLE: return "DOUBLE"; + case BOOL : return "BOOL"; + case ATOM : return "ATOM"; + case STRING: return "STRING"; + case BINARY: return "BINARY"; + case PID : return "PID"; + case PORT : return "PORT"; + case REF : return "REF"; + case VAR : return "VAR"; + case TUPLE : return "TUPLE"; + case LIST : return "LIST"; + case TRACE : return "TRACE"; + default : return "UNDEFINED"; + } + } + + inline const char* type_to_type_string(eterm_type a_type, bool a_prefix) { + switch (a_type) { + case LONG : return a_prefix ? "::int()" : "int()"; + case DOUBLE: return a_prefix ? "::float()" : "float()"; + case BOOL : return a_prefix ? "::bool()" : "bool()"; + case ATOM : return a_prefix ? "::atom()" : "atom()"; + case STRING: return a_prefix ? "::string()" : "string()"; + case BINARY: return a_prefix ? "::binary()" : "binary()"; + case PID : return a_prefix ? "::pid()" : "pid()"; + case PORT : return a_prefix ? "::port()" : "port()"; + case REF : return a_prefix ? "::ref()" : "ref()"; + case VAR : return a_prefix ? "::var()" : "var()"; + case TUPLE : return a_prefix ? "::tuple()" : "tuple()"; + case LIST : return a_prefix ? "::list()" : "list()"; + case TRACE : return a_prefix ? "::trace()" : "trace()"; + default : return ""; + } + } + } // namespace EIXX_NAMESPACE #endif // _EIXX_DEFAULTS_HPP diff --git a/include/eixx/marshal/eterm.ipp b/include/eixx/marshal/eterm.ipp index b910f06..8577dab 100644 --- a/include/eixx/marshal/eterm.ipp +++ b/include/eixx/marshal/eterm.ipp @@ -39,6 +39,65 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include namespace EIXX_NAMESPACE { + +inline eterm_type type_string_to_type(const char* s, size_t n) { + eterm_type r = UNDEFINED; + + if (n < 3) return r; + + int m = n - 1; + const char* p = s+1; + + switch (s[0]) { + case 'i': + if (strncmp(p,"nt",m) == 0) r = LONG; + if (strncmp(p,"nteger",m) == 0) r = LONG; + break; + case 'd': + if (strncmp(p,"ouble",m) == 0) r = DOUBLE; + break; + case 'f': + if (strncmp(p,"loat",m) == 0) r = DOUBLE; + break; + case 'b': + if (strncmp(p,"ool",m) == 0) r = BOOL; + else if (strncmp(p,"inary",m) == 0) r = BINARY; + else if (strncmp(p,"oolean",m)== 0) r = BOOL; + else if (strncmp(p,"yte",m) == 0) r = LONG; + break; + case 'c': + if (strncmp(p,"har",m) == 0) r = LONG; + break; + case 'a': + if (strncmp(p,"tom",m) == 0) r = ATOM; + break; + case 's': + if (strncmp(p,"tring",m) == 0) r = STRING; + break; + case 'p': + if (strncmp(p,"id",m) == 0) r = PID; + else if (strncmp(p,"ort",m) == 0) r = PORT; + break; + case 'r': + if (strncmp(p,"ef",m) == 0) r = REF; + else if (strncmp(p,"eference",m) == 0) r = REF; + break; + case 'v': + if (strncmp(p,"ar",m) == 0) r = VAR; + break; + case 't': + if (strncmp(p,"uple",m) == 0) r = TUPLE; + else if (strncmp(p,"race",m) == 0) r = TRACE; + break; + case 'l': + if (strncmp(p,"ist",m) == 0) r = LIST; + break; + default: + break; + } + return r; + } + namespace marshal { template diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index baf8d57..ed3606c 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -185,7 +185,7 @@ class epid { * Get the node name from the PID. * @return the node name from the PID. **/ - atom node() const { return m_blob ? m_blob->data()->node : atom::null; } + atom node() const { return m_blob ? m_blob->data()->node : atom::null(); } /** * Get the id number from the PID. diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index e88db21..f386a60 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -140,7 +140,7 @@ class port { * Get the node name from the PORT. * @return the node name from the PORT. **/ - atom node() const { return m_blob ? m_blob->data()->node : atom::null; } + atom node() const { return m_blob ? m_blob->data()->node : atom::null(); } /** * Get the id number from the PORT. diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index f98c830..bca57b4 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -43,7 +43,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace EIXX_NAMESPACE { namespace marshal { namespace detail { - extern const uint32_t s_ref_ids[3]; } // namespace detail /** @@ -93,6 +92,11 @@ class ref { uint64_t id1() const { return m_blob->data()->u.s.id1; } public: + inline static const uint32_t* s_ref_ids() { + static const uint32_t s_ref_ids[] = {0, 0, 0}; + return s_ref_ids; + } + static const ref null; ref() : m_blob(nullptr) {} @@ -170,7 +174,7 @@ class ref { * Get the node name from the REF. * @return the node name from the REF. */ - atom node() const { return m_blob ? m_blob->data()->node : atom::null; } + atom node() const { return m_blob ? m_blob->data()->node : atom::null(); } /** * Get an id number from the REF. @@ -186,7 +190,7 @@ class ref { * Get the id array from the REF. * @return the id array number from the REF. */ - const uint32_t* ids() const { return m_blob ? m_blob->data()->u.ids : detail::s_ref_ids; } + const uint32_t* ids() const { return m_blob ? m_blob->data()->u.ids : s_ref_ids(); } /** * Get the creation number from the REF. diff --git a/src/Makefile.am b/src/Makefile.am index 1d0c92f..3207c0b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -89,7 +89,7 @@ libeixx_la_hdr4_HEADERS = $(eixx_hdrs4:%=../include/@PACKAGE@/%) libeixx_la_hdr5dir = $(includedir)/@PACKAGE@/connect/detail libeixx_la_hdr5_HEADERS = $(eixx_hdrs5:%=../include/@PACKAGE@/%) -libeixx_la_SOURCES = am.cpp atom.cpp defaults.cpp ref.cpp \ +libeixx_la_SOURCES = am.cpp \ basic_otp_node_local.cpp \ $(eixx_headers:%=../include/@PACKAGE@/%) libeixx_la_LTADD = -version-info 1:1:0 -shared diff --git a/src/am.cpp b/src/am.cpp index 9aaa3d6..69e13f8 100644 --- a/src/am.cpp +++ b/src/am.cpp @@ -27,7 +27,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace EIXX_NAMESPACE { - const atom am_ANY_ = atom("_"); const atom am_badrpc = atom("badrpc"); const atom am_call = atom("call"); const atom am_cast = atom("cast"); diff --git a/src/atom.cpp b/src/atom.cpp deleted file mode 100644 index fdf068e..0000000 --- a/src/atom.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* -***** BEGIN LICENSE BLOCK ***** - -This file is part of the eixx (Erlang C++ Interface) Library. - -Copyright (C) 2010 Serge Aleynikov - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -***** END LICENSE BLOCK ***** -*/ - -#include -#include -//#include - -namespace EIXX_NAMESPACE { - - util::atom_table& marshal::atom::atom_table() { - //return boost::details::pool::singleton_default >::instance(); - static util::atom_table s_atom_table; - return s_atom_table; - } - - const atom marshal::atom::null = atom(); - -} // namespace EIXX_NAMESPACE - diff --git a/src/defaults.cpp b/src/defaults.cpp deleted file mode 100644 index 3fce93a..0000000 --- a/src/defaults.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include - -namespace EIXX_NAMESPACE { - - const char* type_to_string(eterm_type a_type) { - switch (a_type) { - case LONG : return "LONG"; - case DOUBLE: return "DOUBLE"; - case BOOL : return "BOOL"; - case ATOM : return "ATOM"; - case STRING: return "STRING"; - case BINARY: return "BINARY"; - case PID : return "PID"; - case PORT : return "PORT"; - case REF : return "REF"; - case VAR : return "VAR"; - case TUPLE : return "TUPLE"; - case LIST : return "LIST"; - case TRACE : return "TRACE"; - default : return "UNDEFINED"; - } - } - - const char* type_to_type_string(eterm_type a_type, bool a_prefix) { - switch (a_type) { - case LONG : return a_prefix ? "::int()" : "int()"; - case DOUBLE: return a_prefix ? "::float()" : "float()"; - case BOOL : return a_prefix ? "::bool()" : "bool()"; - case ATOM : return a_prefix ? "::atom()" : "atom()"; - case STRING: return a_prefix ? "::string()" : "string()"; - case BINARY: return a_prefix ? "::binary()" : "binary()"; - case PID : return a_prefix ? "::pid()" : "pid()"; - case PORT : return a_prefix ? "::port()" : "port()"; - case REF : return a_prefix ? "::ref()" : "ref()"; - case VAR : return a_prefix ? "::var()" : "var()"; - case TUPLE : return a_prefix ? "::tuple()" : "tuple()"; - case LIST : return a_prefix ? "::list()" : "list()"; - case TRACE : return a_prefix ? "::trace()" : "trace()"; - default : return ""; - } - } - - eterm_type type_string_to_type(const char* s, size_t n) { - eterm_type r = UNDEFINED; - - if (n < 3) return r; - - int m = n - 1; - const char* p = s+1; - - switch (s[0]) { - case 'i': - if (strncmp(p,"nt",m) == 0) r = LONG; - if (strncmp(p,"nteger",m) == 0) r = LONG; - break; - case 'd': - if (strncmp(p,"ouble",m) == 0) r = DOUBLE; - break; - case 'f': - if (strncmp(p,"loat",m) == 0) r = DOUBLE; - break; - case 'b': - if (strncmp(p,"ool",m) == 0) r = BOOL; - else if (strncmp(p,"inary",m) == 0) r = BINARY; - else if (strncmp(p,"oolean",m)== 0) r = BOOL; - else if (strncmp(p,"yte",m) == 0) r = LONG; - break; - case 'c': - if (strncmp(p,"har",m) == 0) r = LONG; - break; - case 'a': - if (strncmp(p,"tom",m) == 0) r = ATOM; - break; - case 's': - if (strncmp(p,"tring",m) == 0) r = STRING; - break; - case 'p': - if (strncmp(p,"id",m) == 0) r = PID; - else if (strncmp(p,"ort",m) == 0) r = PORT; - break; - case 'r': - if (strncmp(p,"ef",m) == 0) r = REF; - else if (strncmp(p,"eference",m) == 0) r = REF; - break; - case 'v': - if (strncmp(p,"ar",m) == 0) r = VAR; - break; - case 't': - if (strncmp(p,"uple",m) == 0) r = TUPLE; - else if (strncmp(p,"race",m) == 0) r = TRACE; - break; - case 'l': - if (strncmp(p,"ist",m) == 0) r = LIST; - break; - default: - break; - } - return r; - } - -} // namespace EIXX_NAMESPACE - diff --git a/src/ref.cpp b/src/ref.cpp deleted file mode 100644 index 8616e67..0000000 --- a/src/ref.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* -***** BEGIN LICENSE BLOCK ***** - -This file is part of the eixx (Erlang C++ Interface) Library. - -Copyright (C) 2010 Serge Aleynikov - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -***** END LICENSE BLOCK ***** -*/ - -#include -#include - -namespace EIXX_NAMESPACE { - - const uint32_t marshal::detail::s_ref_ids[] = {0, 0, 0}; - -} // namespace EIXX_NAMESPACE - From 41788790aea1f53044311ac02159d0be6b47994e Mon Sep 17 00:00:00 2001 From: erlanger Date: Tue, 25 Nov 2014 03:13:20 -0500 Subject: [PATCH 036/185] portability enhancements, allow 32-bit platform --- include/eixx/eterm.hpp | 22 +++++++++++----------- include/eixx/marshal/eterm.hpp | 12 ++++++------ include/eixx/marshal/pid.hpp | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index 186d8ad..1bf9e01 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -54,17 +54,17 @@ typedef marshal::eterm_pattern_matcher eterm_pattern_matcher; typedef marshal::eterm_pattern_action eterm_pattern_action; namespace detail { - BOOST_STATIC_ASSERT(sizeof(eterm) == 2*sizeof(void*)); - BOOST_STATIC_ASSERT(sizeof(atom) == sizeof(int)); - BOOST_STATIC_ASSERT(sizeof(string) == sizeof(void*)); - BOOST_STATIC_ASSERT(sizeof(binary) == sizeof(void*)); - BOOST_STATIC_ASSERT(sizeof(epid) == sizeof(void*)); - BOOST_STATIC_ASSERT(sizeof(port) == sizeof(void*)); - BOOST_STATIC_ASSERT(sizeof(ref) == sizeof(void*)); - BOOST_STATIC_ASSERT(sizeof(tuple) == sizeof(void*)); - BOOST_STATIC_ASSERT(sizeof(list) == sizeof(void*)); - BOOST_STATIC_ASSERT(sizeof(trace) == sizeof(void*)); - BOOST_STATIC_ASSERT(sizeof(var) == sizeof(void*)); + BOOST_STATIC_ASSERT(sizeof(eterm) == 2*sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(atom) <= sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(string) <= sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(binary) <= sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(epid) <= sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(port) <= sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(ref) <= sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(tuple) <= sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(list) <= sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(trace) <= sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(var) == sizeof(uint64_t)); } // namespace detail } // namespace EIXX_NAMESPACE diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 9f88e11..18185cc 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -147,15 +147,15 @@ class eterm { list l; trace trc; - void* value; // this is for ease of copying + uint64_t value; // this is for ease of copying // We ensure that the size of each compound type - // is sizeof(void*). Therefore it's safe to store the actual - // value of a compound type in this union, so the pointer serves - // as the value placeholder. + // is sizeof(uint64_t). Therefore it's safe to store the actual + // value of a compound type in this union, so the uint64 integer + // acts as the value placeholder. // This allows us to have the minimum overhead related to // copying terms as for simple types it merely involves copying - // 16 bytes (64-bit platform) and for compound types it means copying + // 16 bytes and for compound types it means copying // the same 16 bytes and in some cases // incrementing compound type's reference count. // This approach was tested against boost::variant<> and was found @@ -182,7 +182,7 @@ class eterm { void reset() { i = 0; } } vt; - BOOST_STATIC_ASSERT(sizeof(vartype) == sizeof(void*)); + BOOST_STATIC_ASSERT(sizeof(vartype) == sizeof(uint64_t)); void check(eterm_type tp) const { if (unlikely(m_type != tp)) throw err_wrong_type(tp, m_type); } diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index ed3606c..af7a6f2 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -77,7 +77,7 @@ class epid { {} }; - BOOST_STATIC_ASSERT(sizeof(pid_blob) == sizeof(void*)); + BOOST_STATIC_ASSERT(sizeof(pid_blob) == sizeof(uint64_t)); blob* m_blob; From c45f917d8291f5dd3de1eba8f06e2512ff3765ea Mon Sep 17 00:00:00 2001 From: erlanger Date: Tue, 25 Nov 2014 15:07:10 -0500 Subject: [PATCH 037/185] header-only marshalling, no need for ./configure --- include/eixx/util/common.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/eixx/util/common.hpp b/include/eixx/util/common.hpp index dc4e1a2..18f9507 100644 --- a/include/eixx/util/common.hpp +++ b/include/eixx/util/common.hpp @@ -21,7 +21,9 @@ #include #include +#ifdef HAVE_CONFIG_H #include +#endif #define ERL_MONITOR_P 19 #define ERL_DEMONITOR_P 20 From d9f43f4dc3b8495200fc78b1859d07e4dae9e56f Mon Sep 17 00:00:00 2001 From: erlanger Date: Tue, 25 Nov 2014 15:20:22 -0500 Subject: [PATCH 038/185] doc fixes - header-only marshalling --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3dafd16..e8b149a 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,13 @@ This library adds on the following features: - Global atom table for fast manipulation of atoms. The library consists of two separate parts: - - Term marshaling (included by marshal.hpp or eixx.hpp) + - Term marshaling (included by eterm.hpp or eixx.hpp). - Distributed node connectivity (included by connect.hpp or eixx.hpp) +If you are simply doing term marshalling only the eterm.hpp header along +with one of the alloc headers is needed. This allows for header-only +usage of the marshalling capabilities. + The connectivity library implements a richer set of features than what's available in erl_interface - it fully supports process linking and monitoring. The library is fully asynchronous and allows From 191dae6a3ae9a790e75e80b760721fd38c93b5d5 Mon Sep 17 00:00:00 2001 From: George Evmenov Date: Wed, 3 Dec 2014 13:14:15 +0300 Subject: [PATCH 039/185] fix compilation under clang --- include/eixx/marshal/list.ipp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eixx/marshal/list.ipp b/include/eixx/marshal/list.ipp index 86da4bb..c759882 100644 --- a/include/eixx/marshal/list.ipp +++ b/include/eixx/marshal/list.ipp @@ -52,7 +52,7 @@ void list::init(const eterm* items, size_t N, const Alloc& alloc) l_header->alloc_size = n; l_header->size = N; - for(auto p = items, *end = items+N; p != end; ++p, ++hd) { + for(auto p = items, end = items+N; p != end; ++p, ++hd) { BOOST_ASSERT(p->initialized()); new (&hd->node) eterm(*p); hd->next = hd+1; From d5839dbedbd694e60ee81e9208fac86a4742f207 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 8 Dec 2014 12:45:07 -0500 Subject: [PATCH 040/185] Some clang compilation fixes --- include/eixx/marshal/list.ipp | 2 +- include/eixx/marshal/tuple.hpp | 2 +- include/eixx/marshal/visit.hpp | 4 ++-- src/test_node.cpp | 11 ++++++++--- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/include/eixx/marshal/list.ipp b/include/eixx/marshal/list.ipp index 86da4bb..c362141 100644 --- a/include/eixx/marshal/list.ipp +++ b/include/eixx/marshal/list.ipp @@ -52,7 +52,7 @@ void list::init(const eterm* items, size_t N, const Alloc& alloc) l_header->alloc_size = n; l_header->size = N; - for(auto p = items, *end = items+N; p != end; ++p, ++hd) { + for(const eterm* p = items, *end = items+N; p != end; ++p, ++hd) { BOOST_ASSERT(p->initialized()); new (&hd->node) eterm(*p); hd->next = hd+1; diff --git a/include/eixx/marshal/tuple.hpp b/include/eixx/marshal/tuple.hpp index 13f12df..2b4e0a4 100644 --- a/include/eixx/marshal/tuple.hpp +++ b/include/eixx/marshal/tuple.hpp @@ -45,7 +45,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace EIXX_NAMESPACE { namespace marshal { -template class eterm; +template struct eterm; template class tuple { diff --git a/include/eixx/marshal/visit.hpp b/include/eixx/marshal/visit.hpp index 1618049..8c6f819 100644 --- a/include/eixx/marshal/visit.hpp +++ b/include/eixx/marshal/visit.hpp @@ -38,8 +38,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace EIXX_NAMESPACE { namespace marshal { - template class tuple; - template class list; + template struct tuple; + template struct list; class var; template diff --git a/src/test_node.cpp b/src/test_node.cpp index f61c6e1..016a854 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -58,11 +58,16 @@ bool on_main_msg(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) { if (l_msg.match(s_now_pattern, &l_binding)) { struct timeval tv = { l_binding[N1]->to_long() * 1000000 + - l_binding[N2]->to_long(), - l_binding[N3]->to_long() }; + l_binding[N2]->to_long(), + l_binding[N3]->to_long() }; struct tm tm; localtime_r(&tv.tv_sec, &tm); - printf("Server time: %02d:%02d:%02d.%06ld\n", + printf( +#ifdef __APPLE__ + "Server time: %02d:%02d:%02d.%06d\n", +#else + "Server time: %02d:%02d:%02d.%06ld\n", +#endif tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); } else if (l_msg.match(s_stop)) { a_mbox.node().stop(); From ab219213a71ba8062f591684f7876a5c620929ad Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 8 Dec 2014 13:37:41 -0500 Subject: [PATCH 041/185] Added string to std::string conversion method --- include/eixx/marshal/string.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index a742d1a..9614e05 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -140,6 +140,7 @@ class string const char* c_str() const { return m_blob ? m_blob->data() : ""; } size_t size() const { return m_blob ? m_blob->size()-1 : 0; } + std::string to_str() const { return m_blob ? std::string(m_blob->data(), m_blob->size()-1) : ""; } size_t length() const { return size(); } bool empty() const { return c_str()[0] == '\0'; } From a1ba97bd7b7f4a761033416aae854481f76f7995 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 8 Dec 2014 13:51:02 -0500 Subject: [PATCH 042/185] Added string to std::string conversion method --- include/eixx/marshal/eterm.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 18185cc..72329e9 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -412,6 +412,7 @@ class eterm { const atom& to_atom() const { check(ATOM); return vt.a; } const var& to_var() const { check(VAR); return vt.v; } const string& to_str() const { check(STRING); return vt.s; } + const std::string as_str() const { check(STRING); return vt.s.to_str(); } const binary& to_binary() const { check(BINARY); return vt.bin; } const epid& to_pid() const { check(PID); return vt.pid; } const port& to_port() const { check(PORT); return vt.prt; } From cda3d1e4bd941dc326fd46e58ca5b9d6bb6b4367 Mon Sep 17 00:00:00 2001 From: George Evmenov Date: Fri, 19 Dec 2014 12:00:08 +0300 Subject: [PATCH 043/185] avoid using size of non-static data member (doesnt't compile with clang for some reason) --- include/eixx/marshal/ref.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index bca57b4..d8edaab 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -200,7 +200,7 @@ class ref { bool operator==(const ref& t) const { return node() == t.node() && - ::memcmp(&m_blob->data()->u, &t.m_blob->data()->u, sizeof(ref_blob::u)) == 0; + ::memcmp(&m_blob->data()->u, &t.m_blob->data()->u, sizeof(&m_blob->data()->u)) == 0; } /// Less operator, needed for maps From be849af1187f125ee78c39c256f5903c68c82011 Mon Sep 17 00:00:00 2001 From: George Evmenov Date: Fri, 6 Feb 2015 17:11:22 +0300 Subject: [PATCH 044/185] fix compilation of eixx itself under clang --- README.md | 4 ++++ include/eixx/connect/basic_otp_mailbox.hpp | 6 +++--- include/eixx/connect/basic_otp_node.hpp | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e8b149a..179b9e0 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,10 @@ Run: $ make $ make install # Default install path is ./install +For clang add before ./configure: + $ CC="clang -DBOOST_ASIO_HAS_STD_CHRONO" CXX="clang++ -DBOOST_ASIO_HAS_STD_CHRONO" ./configure <...> + + ### Author ### Serge Aleynikov diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index 9d76af6..b5ee8a2 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -102,10 +102,10 @@ class basic_otp_mailbox typedef util::async_queue*, Alloc> queue_type; template friend class basic_otp_node; - template friend class util::async_queue; + template friend struct util::async_queue; template friend class basic_otp_mailbox_registry; - template friend class std::function; - template friend class std::_Function_handler; + template friend class std::function; + template friend class std::_Function_handler; private: boost::asio::io_service& m_io_service; diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index 75ac443..c6e6d87 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_BASIC_OTP_NODE_HPP_ #define _EIXX_BASIC_OTP_NODE_HPP_ +#include #include #include #include From 4a866bf7102324669ae7a2fddcd935e791a55b55 Mon Sep 17 00:00:00 2001 From: George Evmenov Date: Fri, 6 Feb 2015 17:23:42 +0300 Subject: [PATCH 045/185] fix forward declaration inconsistency (some classes are declared as struct instead of class and vice versa) --- include/eixx/marshal/defaults.hpp | 6 +++--- include/eixx/marshal/tuple.hpp | 2 +- include/eixx/marshal/visit.hpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/eixx/marshal/defaults.hpp b/include/eixx/marshal/defaults.hpp index 52ef2c8..be1acf1 100644 --- a/include/eixx/marshal/defaults.hpp +++ b/include/eixx/marshal/defaults.hpp @@ -40,9 +40,9 @@ namespace EIXX_NAMESPACE { namespace marshal { // Forward declarations - template struct eterm; - template struct tuple; - template struct list; + template class eterm; + template class tuple; + template class list; namespace marshal { template struct visit_eterm_stringify; diff --git a/include/eixx/marshal/tuple.hpp b/include/eixx/marshal/tuple.hpp index 2b4e0a4..13f12df 100644 --- a/include/eixx/marshal/tuple.hpp +++ b/include/eixx/marshal/tuple.hpp @@ -45,7 +45,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace EIXX_NAMESPACE { namespace marshal { -template struct eterm; +template class eterm; template class tuple { diff --git a/include/eixx/marshal/visit.hpp b/include/eixx/marshal/visit.hpp index 8c6f819..1618049 100644 --- a/include/eixx/marshal/visit.hpp +++ b/include/eixx/marshal/visit.hpp @@ -38,8 +38,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace EIXX_NAMESPACE { namespace marshal { - template struct tuple; - template struct list; + template class tuple; + template class list; class var; template From 5135f717ff55043e3c5a6d8ff01b14ef0479519e Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 12 Apr 2015 06:27:02 -0400 Subject: [PATCH 046/185] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 179b9e0..d0bbb13 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ of Erlang terms between processes as well as connecting to other distributed Erlang nodes from a C++ application. The marshaling classes are built on top of ei library included in -{@link http://www.erlang.org/doc/apps/erl_interface erl_interface}. -It is largely inspired by the {@link http://code.google.com/p/epi epi} +http://www.erlang.org/doc/apps/erl_interface. +It is largely inspired by the http://code.google.com/p/epi project, but is a complete rewrite with many new features and optimization enhancements. From 81acf9c2f1da8fab272d59668baabef282016b73 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 12 Apr 2015 06:27:54 -0400 Subject: [PATCH 047/185] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d0bbb13..be4624e 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,8 @@ what's available in erl_interface - it fully supports process linking and monitoring. The library is fully asynchronous and allows handling many connections and mailboxes in one OS thread. -Ths library is dependend on {@link http://www.boost.org BOOST} -project and erl_interface, which is a part of the -{@link www.erlang.org Erlang} distribution. +Ths library is dependend on http://www.boost.org project and +erl_interface, which is a part of the www.erlang.org distribution. ### Downloading ### From 6fae17e181a461eace70d90e2cb45f5646a49387 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 26 May 2015 01:44:26 -0400 Subject: [PATCH 048/185] Replace boost with std --- include/eixx/marshal/eterm_match.hpp | 10 +++++++++- test/test_eterm_match.cpp | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index 61b373b..5593b25 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -79,7 +79,7 @@ class eterm_pattern_matcher { * patterns in the match list shouldn't be checked, the * functor must return true. */ - typedef boost::function< + typedef std::function< bool (const eterm& a_pattern, const varbind& a_binding, long a_opaque) > pattern_functor_t; @@ -229,6 +229,14 @@ class eterm_pattern_action { BOOST_ASSERT(m_fun != NULL); } + template + eterm_pattern_action( + const eterm& a_pattern, const Lambda& a_fun, long a_opaque = 0) + : m_pattern(a_pattern), m_fun(a_fun), m_opaque(a_opaque) + { + BOOST_ASSERT(m_fun != NULL); + } + eterm_pattern_action( const Alloc& a_alloc, pattern_functor_t& a_fun, long a_opaque, const char* a_pat_fmt, ...) diff --git a/test/test_eterm_match.cpp b/test/test_eterm_match.cpp index 3b18922..287cbe6 100644 --- a/test/test_eterm_match.cpp +++ b/test/test_eterm_match.cpp @@ -352,7 +352,7 @@ static void run(int n) { eterm(12345), 4 } }; - static eterm_pattern_matcher sp(list, boost::ref(cb), alloc); + static eterm_pattern_matcher sp(list, std::ref(cb), alloc); BOOST_REQUIRE_EQUAL(n == 1 ? 4u : 3u, sp.size()); From b7f49948570b4950b8d2a0e8a12b0b8845649589 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 26 May 2015 02:00:56 -0400 Subject: [PATCH 049/185] Add copy assignment --- include/eixx/marshal/eterm_match.hpp | 14 ++++++++++++++ include/eixx/marshal/ref.hpp | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index 5593b25..8980c62 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -262,6 +262,20 @@ class eterm_pattern_action { , m_opaque(a_rhs.m_opaque) {} + void operator=(eterm_pattern_action&& a_rhs) + { + m_pattern = std::move(a_rhs.m_pattern); + m_fun = std::move(a_rhs.m_fun); + m_opaque = a_rhs.m_opaque; + } + + void operator=(const eterm_pattern_action& a_rhs) + { + m_pattern = a_rhs.m_pattern; + m_fun = a_rhs.m_fun; + m_opaque = a_rhs.m_opaque; + } + bool operator() (const eterm& a_term, varbind* a_binding) const throw (eterm_exception) diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index d8edaab..de1df5b 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -200,7 +200,7 @@ class ref { bool operator==(const ref& t) const { return node() == t.node() && - ::memcmp(&m_blob->data()->u, &t.m_blob->data()->u, sizeof(&m_blob->data()->u)) == 0; + ::memcmp(&m_blob->data()->u, &t.m_blob->data()->u, sizeof(m_blob->data()->u)) == 0; } /// Less operator, needed for maps From 3717c9929c768db4d4f9037c0508f28dc83e0876 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Fri, 20 Nov 2015 12:45:40 -0500 Subject: [PATCH 050/185] Fix CLANG compilation warning --- include/eixx/marshal/eterm_format.ipp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/eixx/marshal/eterm_format.ipp b/include/eixx/marshal/eterm_format.ipp index 4aa223f..1224d33 100644 --- a/include/eixx/marshal/eterm_format.ipp +++ b/include/eixx/marshal/eterm_format.ipp @@ -105,7 +105,7 @@ namespace marshal { } } - static var pvariable(const char **fmt) + static inline var pvariable(const char **fmt) { const char* start = *fmt, *p = start; char c; @@ -145,7 +145,7 @@ namespace marshal { } /* pvariable */ - static atom patom(const char **fmt) + static inline atom patom(const char **fmt) { skip_ws_and_comments(fmt); @@ -158,7 +158,7 @@ namespace marshal { return atom(start, p - start); } /* patom */ - static atom pquotedatom(const char **fmt) + static inline atom pquotedatom(const char **fmt) { ++(*fmt); /* skip first quote */ //skip_ws_and_comments(fmt); From fc85c6add434e980b052befabf6a23a51e5717e9 Mon Sep 17 00:00:00 2001 From: "Matwey V. Kornilov" Date: Fri, 27 Nov 2015 23:10:13 +0300 Subject: [PATCH 051/185] Assert that sizeof(eterm) platform independently eterm constists of enum (which is supposed to be 4 bytes long) and union (which is 8 bytes long). Aligning is the platform dependent. On the some platforms (i.e. x86_32) the actual size of eterm is 12 bytes. --- configure.ac | 2 ++ include/eixx/eterm.hpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f23554a..74a034b 100644 --- a/configure.ac +++ b/configure.ac @@ -98,6 +98,8 @@ AC_TYPE_SIZE_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T +AC_CHECK_ALIGNOF([uint64_t]) + # Checks for library functions. AC_CHECK_FUNCS([gettimeofday socket sqrt]) diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index 1bf9e01..a817e36 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -54,7 +54,7 @@ typedef marshal::eterm_pattern_matcher eterm_pattern_matcher; typedef marshal::eterm_pattern_action eterm_pattern_action; namespace detail { - BOOST_STATIC_ASSERT(sizeof(eterm) == 2*sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(eterm) == (EIXX_ALIGNOF_UINT64_T > sizeof(int) ? EIXX_ALIGNOF_UINT64_T : sizeof(int)) + sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(atom) <= sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(string) <= sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(binary) <= sizeof(uint64_t)); From 78a3dbb3611b5f3b66a79462dc60b78fb3efc047 Mon Sep 17 00:00:00 2001 From: "Matwey V. Kornilov" Date: Fri, 27 Nov 2015 23:18:20 +0300 Subject: [PATCH 052/185] Fix test_eterm_encode for platforms with sizeof(long) < 8 Add AC_CHECK_SIZEOF to configure.ac to detect size of long on the current platform. 12345678901 is too big to fit into 4 bytes, so we introduce alternative test case of such platforms. This also fix the following warning: test_eterm_encode.cpp:139:18: warning: overflow in implicit constant conversion [-Woverflow] long d = 12345678901; --- configure.ac | 1 + test/test_eterm_encode.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/configure.ac b/configure.ac index 74a034b..a3dc104 100644 --- a/configure.ac +++ b/configure.ac @@ -99,6 +99,7 @@ AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_CHECK_ALIGNOF([uint64_t]) +AC_CHECK_SIZEOF([long]) # Checks for library functions. AC_CHECK_FUNCS([gettimeofday socket sqrt]) diff --git a/test/test_eterm_encode.cpp b/test/test_eterm_encode.cpp index f541f4d..5ce0aff 100644 --- a/test/test_eterm_encode.cpp +++ b/test/test_eterm_encode.cpp @@ -136,10 +136,18 @@ BOOST_AUTO_TEST_CASE( test_encode_long ) BOOST_REQUIRE_EQUAL(d, t1.to_long()); } { +#if EIXX_SIZEOF_LONG >= 8 long d = 12345678901; +#else + long d = 0x12345678; +#endif // EIXX_SIZEOF_LONG >= 8 eterm t(d); string s(t.encode(0)); +#if EIXX_SIZEOF_LONG >= 8 const uint8_t expect[] = {131,110,5,0,53,28,220,223,2}; +#else + const uint8_t expect[] = {131,110,4,0,0x78,0x56,0x34,0x12}; +#endif // EIXX_SIZEOF_LONG >= 8 BOOST_REQUIRE(s.equal(expect)); int idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); From 37ece8e0068c2dc523443d7a0cbfb541852d5197 Mon Sep 17 00:00:00 2001 From: "Matwey V. Kornilov" Date: Sun, 29 Nov 2015 15:59:00 +0300 Subject: [PATCH 053/185] Reimplement bit_scan_forward using __builtin_ctzl __builtin_ctzl is supported by both gcc and clang compilers and provides a way to count trailing zero bits for long variable. On x86 platforms __builtin_ctzl leads to the replaced implementation (using bsfq instruction). --- include/eixx/util/common.hpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/include/eixx/util/common.hpp b/include/eixx/util/common.hpp index 18f9507..ab8be62 100644 --- a/include/eixx/util/common.hpp +++ b/include/eixx/util/common.hpp @@ -75,15 +75,8 @@ int __inline__ log2(unsigned long n, uint8_t base = 2) { } static __inline__ unsigned long bit_scan_forward(unsigned long v) -{ - unsigned long r; - __asm__ __volatile__( - #if (__SIZEOF_LONG__ == 8) - "bsfq %1, %0": "=r"(r): "rm"(v) ); - #else - "bsfl %1, %0": "=r"(r): "rm"(v) ); - #endif - return r; +{ + return __builtin_ctzl(v); } /// Wrapper for basic atomic operations over an integer. From bd8b2bbdd3cd1e03c1bd15e0c71dff9863fd101d Mon Sep 17 00:00:00 2001 From: "Matwey V. Kornilov" Date: Sun, 29 Nov 2015 20:15:36 +0300 Subject: [PATCH 054/185] Handle UB in bit_scan_forward Commit 37ece8e0068c2dc523443d7a0cbfb541852d5197 introduced UB into bit_scan_forward when called with zero agrument. Check m_type == UNDEFINED explicitly in to_type() Also replace bit_scan_forward return type to int to avoid double conevtion. --- include/eixx/connect/transport_msg.hpp | 2 +- include/eixx/util/common.hpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/eixx/connect/transport_msg.hpp b/include/eixx/connect/transport_msg.hpp index a63b2e0..8a9e942 100644 --- a/include/eixx/connect/transport_msg.hpp +++ b/include/eixx/connect/transport_msg.hpp @@ -108,7 +108,7 @@ class transport_msg { /// Transport message type transport_msg_type type() const { return m_type; } - int to_type() const { return bit_scan_forward(m_type); } + int to_type() const { return m_type == UNDEFINED ? 0 : bit_scan_forward(m_type); } const tuple& cntrl() const { return m_cntrl;} const eterm& msg() const { return m_msg; } /// Returns true when the transport message contains message payload diff --git a/include/eixx/util/common.hpp b/include/eixx/util/common.hpp index ab8be62..814fdbf 100644 --- a/include/eixx/util/common.hpp +++ b/include/eixx/util/common.hpp @@ -74,7 +74,8 @@ int __inline__ log2(unsigned long n, uint8_t base = 2) { return n == 1 ? 0 : 1+log2(n/base, base); } -static __inline__ unsigned long bit_scan_forward(unsigned long v) +/// Note, that bit_scan_forward(0) leads to UB +static __inline__ int bit_scan_forward(unsigned long v) { return __builtin_ctzl(v); } From 29202db745a3d79b5209e487fe9bc70b6c73ad9f Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 1 Dec 2015 19:16:41 -0500 Subject: [PATCH 055/185] Add rpath --- configure.ac | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index f23554a..4b906ee 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,8 @@ AC_ARG_VAR([ERLC_FLAGS], [general flags to prepend to ERLC_FLAGS]) ERLC_FLAGS="${ERLC_FLAGS} +debug_info" # CXXFLAGS="${CXXFLAGS% } -MMD -Wall -fno-strict-aliasing -fpermissive -Wl,-V" -CXXFLAGS="${CXXFLAGS% } -MMD -Wall -Wno-unused-local-typedefs -fno-strict-aliasing -std=c++11 -DBOOST_SYSTEM_NO_DEPRECATED=1" +CXXFLAGS="${CXXFLAGS% } -MMD -Wall -Wno-unused-local-typedefs -fno-strict-aliasing" +CXXFLAGS+=" -Wno-deprecated-declarations -std=c++11 -DBOOST_SYSTEM_NO_DEPRECATED=1" AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debug [[default=no]]]), @@ -80,7 +81,7 @@ AX_BOOST_SYSTEM AX_BOOST_ASIO AX_BOOST_DATE_TIME # workaround unexpected extra dependency on boost_system library (at least in 1.49) -LDFLAGS+=" $BOOST_LDFLAGS $BOOST_SYSTEM_LIB" +LDFLAGS+=" $BOOST_LDFLAGS $BOOST_SYSTEM_LIB -Wl,-rpath=${BOOST_LDFLAGS#-L}" AX_BOOST_THREAD AX_BOOST_UNIT_TEST_FRAMEWORK @@ -145,7 +146,8 @@ Erlang not found. Fill the ERL variable with erl(1) path or provide Erlang prefix with --with-erlang.]) fi -AC_SUBST([EI_LDFLAGS], ["-L${ERLANG_LIB_DIR_erl_interface}/lib"]) +AC_SUBST([EI_LDFLAGS], ["-L${ERLANG_LIB_DIR_erl_interface}/lib" + -Wl,-rpath=${ERLANG_LIB_DIR_erl_interface}/lib]) AC_SUBST([EI_LIB], ["-lei"]) AC_CHECK_HEADERS([${ERLANG_LIB_DIR_erl_interface}/src/epmd/ei_epmd.h], From 5bda48f633353b11a369552da29b84d55bfb9a51 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 1 Dec 2015 22:52:35 -0500 Subject: [PATCH 056/185] Add safety guard --- include/eixx/connect/basic_otp_mailbox.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index b5ee8a2..0ff46d8 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -231,14 +231,16 @@ class basic_otp_mailbox /// Deliver a message to this mailbox. The call is thread-safe. void deliver(const transport_msg& a_msg) { - transport_msg* p = new transport_msg(a_msg); - m_queue->enqueue(p); + std::unique_ptr> p(new transport_msg(a_msg)); + m_queue->enqueue(p.get()); + p.release(); } /// Deliver a message to this mailbox. The call is thread-safe. void deliver(transport_msg&& a_msg) { - transport_msg* p = new transport_msg(std::move(a_msg)); - m_queue->enqueue(p); + std::unique_ptr> p(new transport_msg(std::move(a_msg))); + m_queue->enqueue(p.get()); + p.release(); } /// Send a message \a a_msg to a pid \a a_to. From 2481a2b391d17ceafc53c53aeb0a27b55c260c17 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 1 Dec 2015 22:57:08 -0500 Subject: [PATCH 057/185] Remove supurfluous rpath --- configure.ac | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index e214af4..045084c 100644 --- a/configure.ac +++ b/configure.ac @@ -149,8 +149,7 @@ Erlang not found. Fill the ERL variable with erl(1) path or provide Erlang prefix with --with-erlang.]) fi -AC_SUBST([EI_LDFLAGS], ["-L${ERLANG_LIB_DIR_erl_interface}/lib" - -Wl,-rpath=${ERLANG_LIB_DIR_erl_interface}/lib]) +AC_SUBST([EI_LDFLAGS], ["-L${ERLANG_LIB_DIR_erl_interface}/lib"]) AC_SUBST([EI_LIB], ["-lei"]) AC_CHECK_HEADERS([${ERLANG_LIB_DIR_erl_interface}/src/epmd/ei_epmd.h], From 35adeef15678cb1fdda8592733608beb78abb0d3 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 2 Dec 2015 16:01:43 -0500 Subject: [PATCH 058/185] Fix bug in atom table --- include/eixx/util/atom_table.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 75d6534..073eb9a 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -136,7 +136,7 @@ namespace util { if ((size_t)(n+1) == m_atoms.capacity()) throw std::runtime_error("Atom hash table is full!"); m_atoms.push_back(a_name); - m_index[a_name.c_str()] = n; + m_index[m_atoms.back().c_str()] = n; return n; } private: From 32a082f532d3225a3e4a9895cf9a1e060f2214fb Mon Sep 17 00:00:00 2001 From: "Matwey V. Kornilov" Date: Sun, 6 Dec 2015 18:32:10 +0300 Subject: [PATCH 059/185] Install README.md and LICENSE properly Fix #16 --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 861bb8e..623cc37 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,6 +29,6 @@ EXTRA_DIST = README LICENSE LICENSE.header license.sh \ bootstrap installdir = $(prefix) -install_DATA = README.md LICENSE +dist_doc_DATA = README.md LICENSE .PHONY: docs doc From b0625cc9bef47e367ccd03844099571e097caf2e Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 7 Dec 2015 13:34:03 -0500 Subject: [PATCH 060/185] Add perf tests --- configure.ac | 3 +- test/Makefile.am | 4 +- test/test_perf.cpp | 111 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 88 insertions(+), 30 deletions(-) diff --git a/configure.ac b/configure.ac index f23554a..88fe5ee 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,8 @@ AC_ARG_VAR([ERLC_FLAGS], [general flags to prepend to ERLC_FLAGS]) ERLC_FLAGS="${ERLC_FLAGS} +debug_info" # CXXFLAGS="${CXXFLAGS% } -MMD -Wall -fno-strict-aliasing -fpermissive -Wl,-V" -CXXFLAGS="${CXXFLAGS% } -MMD -Wall -Wno-unused-local-typedefs -fno-strict-aliasing -std=c++11 -DBOOST_SYSTEM_NO_DEPRECATED=1" +CXXFLAGS="${CXXFLAGS% } -MMD -Wall -Wno-unused-local-typedefs -fno-strict-aliasing" +CXXFLAGS+=" -Wno-deprecated-declarations -std=c++11 -DBOOST_SYSTEM_NO_DEPRECATED=1" AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debug [[default=no]]]), diff --git a/test/Makefile.am b/test/Makefile.am index 6a5e77a..6efc669 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -25,8 +25,8 @@ test_connect_LDADD = -L../src/.libs -leixx \ $(BOOST_THREAD_LIB) test_perf_SOURCES = test_perf.cpp -test_perf_CPPFLAGS = -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) +test_perf_CPPFLAGS = -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) -Wno-unused-variable test_perf_LDFLAGS = -L$(ERLANG_LIB_DIR_erl_interface)/lib $(BOOST_LDFLAGS) -test_perf_LDADD = -L../src/.libs -leixx $(BOOST_SYSTEM_LIB) +test_perf_LDADD = -L../src/.libs -leixx -lei $(BOOST_SYSTEM_LIB) diff --git a/test/test_perf.cpp b/test/test_perf.cpp index ee9f974..2ed5148 100644 --- a/test/test_perf.cpp +++ b/test/test_perf.cpp @@ -6,7 +6,7 @@ using namespace EIXX_NAMESPACE; -int iterations=500000; +int iterations=200000; class timer { struct rusage start, end; @@ -14,14 +14,19 @@ class timer { public: timer() { begin(); } - void sample(const char* title, bool restart = true) { + void restart() { begin(); } + + void sample(const char* title, bool restart = true, size_t out = 0) { getrusage(RUSAGE_THREAD, &end); double diff = (double)(end.ru_utime.tv_sec - start.ru_utime.tv_sec + end.ru_stime.tv_sec - start.ru_stime.tv_sec) + (double)(end.ru_utime.tv_usec - start.ru_utime.tv_usec + end.ru_stime.tv_usec - start.ru_stime.tv_usec)/1000000.0; - printf("%30s | %.6f (speed: %5.3fus)\n", title, diff, 1000000.0*diff/iterations); + // out is used merely to trick the optimizer + printf("%30s | latency: %7.3fus, speed: %9ld/s%s", title, + 1000000.0*diff/iterations, diff > 0 ? long((double)iterations / diff) : 0, + out == 0 ? "\n" : " \n"); if (restart) begin(); } @@ -40,62 +45,114 @@ int main(int argc, char* argv[]) { timer tot; timer t; + size_t size = 0; for (int j=0; j < iterations; j++) - { eterm(1); } - t.sample("Integer"); + { size += eterm(1).encode_size(); } + t.sample("Integer", true, size); for (int j=0; j < iterations; j++) - { eterm(1.0); } - t.sample("Double"); + { eterm(1.0).encode_size(); } + t.sample("Double", true, size); for (int j=0; j < iterations; j++) - { eterm(true); } - t.sample("Bool"); + { eterm(true).encode_size(); } + t.sample("Bool", true, size); for (int j=0; j < iterations; j++) - { eterm("test"); } - t.sample("String"); + { eterm("test").encode_size(); } + t.sample("String", true, size); for (int j=0; j < iterations; j++) - { atom("test"); } - t.sample("Atom1"); + { atom("test").encode_size(); } + t.sample("Atom1", true, size); { atom a("test"); int k = 0; for (int j=0; j < iterations; j++) - { atom t("test"); if (t==a) k++; } - t.sample("Atom2"); + { atom t("test"); if (t==a) k++; size += eterm(t).encode_size(); } + t.sample("Atom2", true, size); } static const char* ss="This is a test string. This is a test string. This is a test string."; for (int j=0; j < iterations; j++) { - binary b(ss, sizeof(ss)); + binary b(ss, sizeof(ss)); size += eterm(b).encode_size(); } - t.sample("Binary1"); + t.sample("Binary1", true, size); { binary b(ss, sizeof(ss)); for (int j=0; j < iterations; j++) { eterm t(b); + size += t.encode_size(); } - t.sample("Binary2"); + t.sample("Binary2", true, size); } eterm l[] = { eterm(10), eterm("atom_value"), eterm(true) }; for (int j=0; j < iterations; j++) - { tuple t(l); } - t.sample("Tuple1"); + { tuple t(l); size += eterm(t).encode_size(); } + t.sample("Tuple1", true, size); { tuple tup(l); for (int j=0; j < iterations; j++) - { eterm et(tup); } - t.sample("Tuple2"); + { eterm et(tup); size += et.encode_size(); } + t.sample("Tuple2", true, size); } for (int j=0; j < iterations; j++) - { list t(l); } - t.sample("List1"); + { list t(l); size += eterm(t).encode_size(); } + t.sample("List1", true, size); { list ll(l); for (int j=0; j < iterations; j++) - { eterm et(ll); } - t.sample("List2"); + { eterm et(ll); size += et.encode_size(); } + t.sample("List2", true, size); + } + + static const eterm s_md1 = + eterm::format("{md, Xchg, Instr, [{q, [{BPx,BQty}], [{APx, AQty}]}]}"); + static const eterm s_md2 = + eterm::format("{md, Xchg, Instr, [{q, L1, L2}]}"); + static const atom am_Xchg ("Xchg"); + static const atom am_Instr("Instr"); + static const atom am_BPx ("BPx"); + static const atom am_AQty ("AQty"); + static const atom am_APx ("APx"); + static const atom am_BQty ("BQty"); + static const atom am_L1 ("L1"); + static const atom am_L2 ("L2"); + atom xchg ("CNX"); + atom instr("EUR/USD"); + t.restart(); + { + size_t size = 0; + for (int j=0; j < iterations; j++) { + auto x = s_md1.apply({{am_Xchg, xchg}, {am_Instr, instr}, + {am_BPx, 1.2345}, {am_BQty, 100000}, + {am_APx, 1.2355}, {am_AQty, 200000}}); + size += x.encode_size(); + } + t.sample("Apply speed", true, size); + } + { + size_t size = 0; + for (int j=0; j < iterations; j++) { + auto x = s_md2.apply({{am_Xchg, xchg}, {am_Instr, instr}, + {am_L1, list::make(tuple::make(1.2345, 100000))}, + {am_L2, list::make(tuple::make(1.2355, 200000))}}); + size += x.encode_size(); + } + t.sample("Apply/Create speed", true, size); + } + atom am_md("md"); + atom am_q ("q"); + { + iterations /= 10; + size_t size = 0; + for (int j=0, e = iterations; j < e; j++) { + auto x = tuple::make(am_md, xchg, instr, + list::make(tuple::make(am_q, + list::make(tuple::make(1.2345, 100000)), + list::make(tuple::make(1.2355, 200000))))); + size += x.encode_size(); + } + t.sample("Create speed", true, size); + iterations *= 10; } - tot.sample("Total time"); return 0; } From 336e256de8783b0168fef058695fa4d3efe33e33 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sat, 2 Jan 2016 21:06:01 -0500 Subject: [PATCH 061/185] Add string constructor --- include/eixx/marshal/string.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index 9614e05..2338794 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -62,6 +62,12 @@ class string string() : m_blob(nullptr) {} + string(size_t a_sz, const Alloc& a = Alloc()) + : m_blob(new blob(a_sz+1, a)) + { + m_blob->data()[m_blob->size()-1] = '\0'; + } + string(const char* s, const Alloc& a = Alloc()) { BOOST_ASSERT(s); if (!s[0]) { From e4a48df958f9e6179a3c840b770dec68e45a1319 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 5 Jan 2016 19:16:51 -0500 Subject: [PATCH 062/185] Add badarg atom --- include/eixx/eterm.hpp | 1 + include/eixx/marshal/am.hpp | 1 + src/am.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index a817e36..7487a90 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_ETERM_HPP_ #define _EIXX_ETERM_HPP_ +#include #include // definition of EIXX_NAMESPACE #include #include diff --git a/include/eixx/marshal/am.hpp b/include/eixx/marshal/am.hpp index 02420ee..28f7a6e 100644 --- a/include/eixx/marshal/am.hpp +++ b/include/eixx/marshal/am.hpp @@ -42,6 +42,7 @@ namespace EIXX_NAMESPACE { // Constant global atom values const atom am_ANY_ = atom("_"); + extern const atom am_badarg; extern const atom am_badrpc; extern const atom am_call; extern const atom am_cast; diff --git a/src/am.cpp b/src/am.cpp index 69e13f8..68b3a2f 100644 --- a/src/am.cpp +++ b/src/am.cpp @@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace EIXX_NAMESPACE { + const atom am_badarg = atom("badarg"); const atom am_badrpc = atom("badrpc"); const atom am_call = atom("call"); const atom am_cast = atom("cast"); From ed20b864b2cbbbb6f507b4599293e10c905cf90e Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 7 Jan 2016 11:24:48 -0500 Subject: [PATCH 063/185] Reformat code --- include/eixx/marshal/am.hpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/eixx/marshal/am.hpp b/include/eixx/marshal/am.hpp index 28f7a6e..8ada959 100644 --- a/include/eixx/marshal/am.hpp +++ b/include/eixx/marshal/am.hpp @@ -30,8 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***** END LICENSE BLOCK ***** */ -#ifndef _EIXX_AM_HPP_ -#define _EIXX_AM_HPP_ +#pragma once #include @@ -41,7 +40,7 @@ namespace EIXX_NAMESPACE { // Constant global atom values - const atom am_ANY_ = atom("_"); + const atom am_ANY_ = atom("_"); extern const atom am_badarg; extern const atom am_badrpc; extern const atom am_call; @@ -66,5 +65,3 @@ namespace EIXX_NAMESPACE { extern const atom am_user; } // namespace EIXX_NAMESPACE - -#endif // _EIXX_AM_HPP_ From 878100a9b74f5ce2cfae467a956bcb7bec95ef06 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 11 Jan 2016 08:29:07 -0500 Subject: [PATCH 064/185] Add binary from std::string initialization --- include/eixx/marshal/binary.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/eixx/marshal/binary.hpp b/include/eixx/marshal/binary.hpp index 02c66e3..3dca95b 100644 --- a/include/eixx/marshal/binary.hpp +++ b/include/eixx/marshal/binary.hpp @@ -54,6 +54,11 @@ class binary public: binary() : m_blob(nullptr) {} + /// Create a binary from string + explicit binary(const std::string& a_bin, const Alloc& a_alloc = Alloc()) + : binary(a_bin.c_str(), a_bin.size(), a_alloc) + {} + /** * Create a binary from the given data. * Data is shared between all cloned binaries by using reference counting. From bdf7be834e5f181371f57a04a3fe1d450c3f654a Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 12 Jan 2016 00:16:14 -0500 Subject: [PATCH 065/185] Fix bug in empty string comparison --- include/eixx/marshal/eterm.hpp | 10 ++++++++-- include/eixx/marshal/string.hpp | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 72329e9..555d7f8 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -411,8 +411,14 @@ class eterm { bool to_bool() const { check(BOOL); return vt.b; } const atom& to_atom() const { check(ATOM); return vt.a; } const var& to_var() const { check(VAR); return vt.v; } - const string& to_str() const { check(STRING); return vt.s; } - const std::string as_str() const { check(STRING); return vt.s.to_str(); } + const string& to_str() const { + if (m_type==LIST && vt.l.empty()) return string::null(); + check(STRING); return vt.s; + } + const std::string as_str() const { + if (m_type==LIST && vt.l.empty()) return std::string(); + check(STRING); return vt.s.to_str(); + } const binary& to_binary() const { check(BINARY); return vt.bin; } const epid& to_pid() const { check(PID); return vt.pid; } const port& to_port() const { check(PORT); return vt.prt; } diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index 2338794..b00f0ee 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -60,6 +60,8 @@ class string public: typedef const char* const_iterator; + static const string& null() { static string s; return s; } + string() : m_blob(nullptr) {} string(size_t a_sz, const Alloc& a = Alloc()) From 3027f0ff4a8bee0ddf2fb4e3b2555ce68f55c3b0 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 14 Jan 2016 01:02:00 -0500 Subject: [PATCH 066/185] Add helper methods --- include/eixx/marshal/eterm.hpp | 13 ++++++++++--- include/eixx/marshal/varbind.hpp | 15 ++++++--------- include/eixx/util/async_queue.hpp | 23 ++++++++++------------- src/test_node.cpp | 4 ++-- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 555d7f8..2c381e2 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -400,8 +400,11 @@ class eterm { * Get the string representation of this eterm using a variable binding * @param binding Variable binding to use. It can be null. */ - std::string to_string(size_t a_size_limit = std::string::npos, - const varbind* binding = NULL) const; + std::string to_string(size_t a_size_limit, + const varbind* binding = NULL) const; + + // Separated into a separate function without default args for ease of gdb debugging + std::string to_string() const { return to_string(std::string::npos, NULL); } // Convert a term to its underlying type. Will throw an exception // when the underlying type doesn't correspond to the requested operation. @@ -454,10 +457,14 @@ class eterm { * match succeeds. * @return true if matching succeeded or false if failed. */ - bool match(const eterm& pattern, varbind* binding = NULL, + bool match(const eterm& pattern, varbind* binding, const Alloc& a_alloc = Alloc()) const throw (err_unbound_variable); + // Separated into a separate function without default args for ease of gdb debugging + bool match(const eterm& pattern) const + throw (err_unbound_variable) { return match(pattern, NULL, Alloc()); } + /** * Returns the equivalent without inner variables, using the * given binding to substitute them. diff --git a/include/eixx/marshal/varbind.hpp b/include/eixx/marshal/varbind.hpp index cd057ab..d06e86f 100644 --- a/include/eixx/marshal/varbind.hpp +++ b/include/eixx/marshal/varbind.hpp @@ -160,19 +160,16 @@ class varbind { bind(it->first, it->second); } - /** - * Reset this binding - */ + /// Reset this binding void clear() { m_term_map.clear(); } - /** - * Convert varbind to string - */ + /// Convert varbind to string void dump(std::ostream& out) const { out << *this; } - /** - * Return the number of bound variables held in internal dictionary. - */ + /// Dump to string + std::string to_string() const { std::stringstream s; dump(s); return s.str(); } + + /// Return the number of bound variables held in internal dictionary. size_t count() const { return m_term_map.size(); } protected: diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index 3323db1..dc512a2 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -56,16 +56,12 @@ using namespace boost::system::errc; template> struct async_queue : std::enable_shared_from_this> { - typedef boost::lockfree::queue< - T - , boost::lockfree::allocator - , boost::lockfree::capacity<1023> - , boost::lockfree::fixed_sized - > queue_type; - - typedef std::function< - bool (T&, const boost::system::error_code& ec) - > async_handler; + using queue_type = boost::lockfree::queue + , boost::lockfree::capacity<1023>, + boost::lockfree::fixed_sized>; + + using async_handler = + std::function; private: boost::asio::io_service& m_io; queue_type m_queue; @@ -102,8 +98,7 @@ struct async_queue : std::enable_shared_from_this> // to process - give up the time slice and reschedule the handler if (i == m_batch_size && !m_queue.empty()) { m_io.post([this, h, repeat, repeat_count]() { - (*this->shared_from_this())( - h, boost::asio::error::operation_aborted, repeat, repeat_count); + (*this->shared_from_this())(h, boost::asio::error::operation_aborted, repeat, repeat_count); }); return; } else if (!i && !h(value, s_timeout)) { @@ -219,7 +214,9 @@ struct async_queue : std::enable_shared_from_this> m_timer.async_wait( [this, &a_on_data, timeout, rep] (const boost::system::error_code& e) { - (*this->shared_from_this())(a_on_data, e, timeout, rep); + auto p = this->shared_from_this(); + if (p) + (*p)(a_on_data, e, timeout, rep); } ); } diff --git a/src/test_node.cpp b/src/test_node.cpp index 016a854..b7fa7dd 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -141,11 +141,11 @@ int main(int argc, char* argv[]) { l_node.connect(&on_connect, g_rem_node, reconnect_secs); //otp_connection::connection_type* l_transport = a_con->transport(); - g_io_server->async_receive(&on_io_request, std::chrono::milliseconds(-1), -1); + g_io_server->async_receive(on_io_request, std::chrono::milliseconds(-1), -1); //l_node->send_rpc(self, a_con->remote_node(), atom("shell_default"), atom("ls"), // list::make(), &io_server); - g_main->async_receive(&on_main_msg, std::chrono::seconds(5), -1); + g_main->async_receive(on_main_msg, std::chrono::seconds(5), -1); l_node.run(); From bcf9f93a2682c33c7ee078956c392b5b864c8bb7 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sat, 16 Jan 2016 23:05:49 -0500 Subject: [PATCH 067/185] Migrate build to cmake --- .gitignore | 9 + .kdev_include_paths | 3 + CMakeLists.txt | 235 +++++++ LICENSE | 676 ++++++--------------- LICENSE.header | 20 +- Makefile.am | 34 -- bootstrap | 3 - bootstrap.mk | 141 +++++ build-aux/CMakeEx.txt | 69 +++ build-aux/CMakeInit.txt | 11 + build-aux/erlang.m4 | 87 --- configure.ac | 191 ------ eixx.kdev4 | 3 + src/eixx.pc.in => eixx.pc.in | 0 include/eixx/connect/basic_otp_mailbox.hpp | 45 +- include/eixx/connect/basic_otp_mailbox.ipp | 15 +- include/eixx/util/async_queue.hpp | 13 +- license.sh | 8 +- src/CMakeLists.txt | 30 + src/test_node.cpp | 50 +- test/CMakeLists.txt | 42 ++ 21 files changed, 809 insertions(+), 876 deletions(-) create mode 100644 .kdev_include_paths create mode 100644 CMakeLists.txt delete mode 100644 Makefile.am delete mode 100755 bootstrap create mode 100644 bootstrap.mk create mode 100644 build-aux/CMakeEx.txt create mode 100644 build-aux/CMakeInit.txt delete mode 100644 build-aux/erlang.m4 delete mode 100644 configure.ac create mode 100644 eixx.kdev4 rename src/eixx.pc.in => eixx.pc.in (100%) create mode 100644 src/CMakeLists.txt create mode 100644 test/CMakeLists.txt diff --git a/.gitignore b/.gitignore index 3e0f15d..a6263ca 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,12 @@ test/test_eterm test/*.o test/test_perf test/test_connect +.build/ +.cproject +.kdev4/ +.project +build +inst +test/.kdev4/ +test/test.kdev4 + diff --git a/.kdev_include_paths b/.kdev_include_paths new file mode 100644 index 0000000..ec20600 --- /dev/null +++ b/.kdev_include_paths @@ -0,0 +1,3 @@ +include +/opt/erlang/lib/erlang/lib/erl_interface-3.7.11/include +/opt/boost/include diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..591ce56 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,235 @@ +# vim:ts=2:sw=2:et +cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) +project(eixx VERSION 1.4) + +#=============================================================================== +# CMAKE options customization +#=============================================================================== +option(VERBOSE "Turn verbosity on|off" OFF) +#set(DEBUG "vars") + +if(VERBOSE) + set(CMAKE_VERBOSE_MAKEFILE ON) +endif() +if(WITH_ENUM_SERIALIZATION) + set(UTXX_ENUM_SUPPORT_SERIALIZATION ON) +endif() + +string(TOLOWER ${TOOLCHAIN} toolchain) +string(TOUPPER "${PROJECT_NAME}-${TOOLCHAIN}" BUILD_TYPE) + +# Custom extensions +include(${CMAKE_CURRENT_SOURCE_DIR}/build-aux/CMakeEx.txt) + +#------------------------------------------------------------------------------- +# Toolchain +#------------------------------------------------------------------------------- +# See also build/CMakeInit.txt +if("${toolchain}" STREQUAL "gcc") + set(CMAKE_C_COMPILER "gcc") + set(CMAKE_CXX_COMPILER "g++") + add_definitions(-Wno-strict-aliasing -fopenmp -Wall) + + if("${CMAKE_BUILD_TYPE}" STREQUAL "Release") + add_definitions(-flto -funroll-loops -fomit-frame-pointer) + + # The following will omit all symbol information from the build: + #add_definitions(-Wl,-s) + #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s") + endif() + + #if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release") + # add_definitions(-flto -funroll-loops -fomit-frame-pointer -Wl,-s) + # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s") + #endif() +elseif("${toolchain}" STREQUAL "intel") + set(CMAKE_C_COMPILER "icc") + set(CMAKE_CXX_COMPILER "icpc") + add_definitions(-openmp) + +elseif("${toolchain}" STREQUAL "clang") + set(CMAKE_C_COMPILER "clang") + set(CMAKE_CXX_COMPILER "clang++") + add_definitions(-Wall) +else() + message(FATAL_ERROR "Invalid toolchain: ${TOOLCHAIN}") +endif() + +# Note: explicit c++14 definitions done in CMakeInit.txt. +# Alternative is to set for each target: +# target_compile_features(${PROJECT_NAME} PRIVATE cxx_lambda_init_captures) + +add_definitions( + -D_REENTRANT + -Wno-unused-local-typedefs + -Wno-deprecated-declarations + -DBOOST_SYSTEM_NO_DEPRECATED +) + +message(STATUS "${ClrBold}Configuring for the ${TOOLCHAIN} toolchain${ClrReset}") + +#------------------------------------------------------------------------------- +# Policies +#------------------------------------------------------------------------------- +# Don't curse at non-existing dependencies (since we use code generation) +cmake_policy(SET CMP0046 OLD) + +# RPATH configuration +# =================== +# Don't skip the full RPATH for the build tree +set(CMAKE_SKIP_BUILD_RPATH FALSE) +# When building, don't use the install RPATH already +# (but later on when installing) +set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +set(CMAKE_INSTALL_RPATH "${CMAKE_BINARY_DIR}/src:${CMAKE_INSTALL_PREFIX}/lib") +# Add the automatically determined parts of the RPATH +# which point to directories outside the build tree to the install RPATH +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +#------------------------------------------------------------------------------- +# Platform-specific checks +#------------------------------------------------------------------------------- +#include(${CMAKE_ROOT}/Modules/CheckTypeSize.cmake) +#include(${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake) +#include(${CMAKE_ROOT}/Modules/CheckStructHasMember.cmake) +#include(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) + +#CHECK_INCLUDE_FILE(netinet/in.h HAVE_NETINET_IN_H) +# Needed for pcap.hpp tests +#CHECK_STRUCT_HAS_MEMBER("struct tcphdr" th_flags netinet/tcp.h UTXX_HAVE_TCPHDR_TH_FLAGS_H) + +#------------------------------------------------------------------------------- +# Dependent packages and their directory locations +#------------------------------------------------------------------------------- +find_package(PkgConfig) + +set(PKG_ROOT_DIR "/opt/pkg" CACHE STRING "Package root directory") + +# Python +find_package(PythonInterp) + +# Boost (with local modifications): +set(Boost_USE_STATIC_LIBS OFF) +set(Boost_USE_MULTITHREAD ON) +set(Boost_NO_SYSTEM_PATHS ON) +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/build") + +find_package(Boost 1.55.0 REQUIRED COMPONENTS + system filesystem date_time program_options thread regex + unit_test_framework timer) + +if(Boost_FOUND) + #include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) + #link_directories(${Boost_LIBRARY_DIRS}) + set(UTXX_HAVE_BOOST_TIMER_TIMER_HPP 1) + message(STATUS "Found boost: ${Boost_LIBRARY_DIRS}") +endif() + +set(Boost_LIBRARIES + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_REGEX_LIBRARY} + ${Boost_DATE_TIME_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_IOSTREAMS_LIBRARY} +) + +set(AddCleanFiles) # Additional clean files + +#------------------------------------------------------------------------------- +# MAKE options +#------------------------------------------------------------------------------- + +#add_custom_target(vars +# COMMAND ${CMAKE_COMMAND} -H${CMAKE_SOURCE_DIR} -B${CMAKE_BINARY_DIR} -LA +#) + +include_directories( + SYSTEM + ${Boost_INCLUDE_DIRS} +) +include_directories( + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_BINARY_DIR}/include +) +link_directories( + ${Boost_LIBRARY_DIRS} +) + +#------------------------------------------------------------------------------- +# Configure files +#------------------------------------------------------------------------------- +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/config.h" + @ONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" @ONLY) +#------------------------------------------------------------------------------- +# Srcs and Targets: +#------------------------------------------------------------------------------- + +add_subdirectory(src) +add_subdirectory(test) + +#=============================================================================== +# Installation +#=============================================================================== +install( + DIRECTORY ${CMAKE_SOURCE_DIR}/include/${PROJECT_NAME} + DESTINATION ${CMAKE_INSTALL_PREFIX}/include + FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" PATTERN "*.ipp" PATTERN "*.x??" +) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/config.h + DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${PROJECT_NAME} +) +install( + FILES ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig +) +install( + FILES ${CMAKE_SOURCE_DIR}/LICENSE + ${CMAKE_SOURCE_DIR}/README.md + DESTINATION ${CMAKE_INSTALL_PREFIX}/share +) + +#=============================================================================== +# Uninstallation +# Prereq: copy the uninstall.cmake file to the appropriate CMAKE_MODULE_PATH. +#=============================================================================== +set_directory_properties( + PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${AddCleanFiles}" +) + +#add_custom_target( +# uninstall "${CMAKE_COMMAND}" -P "${CMAKE_MODULE_PATH}/uninstall.cmake" +#) + +#=============================================================================== +# CTEST options +#=============================================================================== +enable_testing() + +add_test(test-utxx test/test-eixx -l message) + +#=============================================================================== +# Documentation options +#=============================================================================== +# add a target to generate API documentation with Doxygen +find_package(Doxygen) +if(DOXYGEN_FOUND) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/build-aux/Doxyfile.in + ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + @ONLY) + add_custom_target(doc + ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "${ClrBold}Generating API documentation with Doxygen${ClrReset}" + VERBATIM + ) +endif() + +# Post-install script (installation of symlinks): +install(SCRIPT ${CMAKE_SOURCE_DIR}/build-aux/install-symlinks.cmake) diff --git a/LICENSE b/LICENSE index 4362b49..e454a52 100644 --- a/LICENSE +++ b/LICENSE @@ -1,502 +1,178 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/LICENSE.header b/LICENSE.header index 12170c2..b1ac255 100644 --- a/LICENSE.header +++ b/LICENSE.header @@ -5,19 +5,17 @@ This project is eixx (Erlang C++ Interface) library. Copyright (C) 2010 Serge Aleynikov -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. + http://www.apache.org/licenses/LICENSE-2.0 -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 623cc37..0000000 --- a/Makefile.am +++ /dev/null @@ -1,34 +0,0 @@ -SUBDIRS = src test -ACLOCAL_AMFLAGS = -I build-aux - -pkgconfigdir = $(libdir)/pkgconfig -nodist_pkgconfig_DATA = src/eixx.pc - -clean-local: - -rm -fr @default_prefix@ - -docs: build-aux/Doxyfile - $(MKDIR_P) @docdir@ - doxygen build-aux/Doxyfile - -build-aux/Doxyfile: build-aux/Doxyfile.in - $(SED) -e 's|[@]docdir@|${docdir}|g' \ - -e 's|[@]PACKAGE@|${PACKAGE}|g' \ - -e 's|[@]PACKAGE_VERSION@|${PACKAGE_VERSION}|g' $< > "$@" - -CLEANFILES = stamp-h1 -DISTCLEANFILES = config.h.in~ config.log build-aux/Doxyfile -MAINTAINERCLEANFILES = configure build-aux/l*.m4 build-aux/*.sh \ - build-aux/config.* build-aux/missing build-aux/depcomp \ - build-aux/install-sh build-aux/Doxyfile \ - aclocal.m4 Makefile.in src/Makefile.in test/Makefile.in \ - src/eixx.pc - -EXTRA_DIST = README LICENSE LICENSE.header license.sh \ - build-aux/boost.m4 build-aux/Doxyfile.in \ - bootstrap - -installdir = $(prefix) -dist_doc_DATA = README.md LICENSE - -.PHONY: docs doc diff --git a/bootstrap b/bootstrap deleted file mode 100755 index 843a281..0000000 --- a/bootstrap +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -autoreconf -v --install diff --git a/bootstrap.mk b/bootstrap.mk new file mode 100644 index 0000000..1a55f08 --- /dev/null +++ b/bootstrap.mk @@ -0,0 +1,141 @@ +# vim:ts=4:sw=4:et +#------------------------------------------------------------------------------- +# Bootstrapping cmake +#------------------------------------------------------------------------------- +# Copyright (c) 2015 Serge Aleynikov +# Date: 2014-08-12 +#------------------------------------------------------------------------------- + +PROJECT := $(shell sed -n '/^project/{s/^project. *\([a-zA-Z0-9]\+\).*/\1/p; q}'\ + CMakeLists.txt) +VERSION := $(shell sed -n '/^project/{s/^.\+VERSION \+//; s/[^\.0-9]\+//; p; q}'\ + CMakeLists.txt) + +HOSTNAME := $(shell hostname) + +# Options file is either: .cmake-args.$(HOSTNAME) or .cmake-args +OPT_FILE := .cmake-args.$(HOSTNAME) +ifeq "$(wildcard $(OPT_FILE))" "" + OPT_FILE := .cmake-args + ifeq "$(wildcard $(OPT_FILE))" "" + OPT_FILE := "/dev/null" + endif +endif + +#------------------------------------------------------------------------------- +# Default target +#------------------------------------------------------------------------------- +all: + @echo + @echo "Run: make bootstrap [toolchain=gcc|clang|intel] [verbose=true] \\" + @echo " [generator=ninja|make] [build=Debug|Release]" + @echo + @echo "To customize cmake variables, create a file with VAR=VALUE pairs:" + @echo " '.cmake-args.$(HOSTNAME)' or '.cmake-args'" + @echo "" + @echo "There are three sets of variables present there:" + @echo " 1. DIR:BUILD=... - Build directory" + @echo " DIR:INSTALL=... - Install directory" + @echo + @echo " They may contain macros:" + @echo " @PROJECT@ - name of current project (from CMakeList.txt)" + @echo " @VERSION@ - project version number (from CMakeList.txt)" + @echo " @BUILD@ - build type (from command line)" + @echo " \$${...} - environment variable" + @echo + @echo " 2. ENV:VAR=... - Environment var set before running cmake" + @echo + @echo " 3. VAR=... - Variable passed to cmake with -D prefix" + @echo + @echo " Lines beginning with '#' are considered to be comments" + @echo + +toolchain ?= gcc +build ?= Debug +# Convert build to lower case: +BUILD := $(shell echo $(build) | tr 'A-Z' 'a-z') + +ifeq (,$(findstring $(BUILD),debug release relwithdefinfo minsizerel)) + $(error Invalid build type: $(build)) +endif + +# Function that replaces variables in a given entry in a file +# E.g.: $(call substitute,ENTRY,FILENAME) +substitute = $(shell sed -n '/^$(1)=/{s!$(1)=!!; s!/\+$$!!; \ + s!@PROJECT@!$(PROJECT)!gI; \ + s!@VERSION@!$(VERSION)!gI; \ + s!@BUILD@!$(BUILD)!gI; \ + p; q}' $(2) 2>/dev/null) +BLD_DIR := $(call substitute,DIR:BUILD,$(OPT_FILE)) +ROOT_DIR := $(dir $(abspath include)) +DEF_BLD_DIR := $(ROOT_DIR:%/=%)/build +DIR := $(if $(BLD_DIR),$(BLD_DIR),$(DEF_BLD_DIR)) +PREFIX := $(call substitute,DIR:INSTALL,$(OPT_FILE)) +prefix := $(if $(PREFIX),$(PREFIX),/usr/local) +generator ?= make + +#------------------------------------------------------------------------------- +# info target +#------------------------------------------------------------------------------- +info: + @echo "PROJECT: $(PROJECT)" + @echo "HOSTNAME: $(HOSTNAME)" + @echo "VERSION: $(VERSION)" + @echo "OPT_FILE: $(OPT_FILE)" + @echo "BLD_DIR: $(BLD_DIR)" + @echo "DIR: $(DIR)" + @echo "build: $(BUILD)" + @echo "prefix: $(prefix)" + @echo "generator: $(generator)" + +variables := $(filter-out toolchain=% generator=% build=% verbose=%,$(MAKEOVERRIDES)) +makevars := $(variables:%=-D%) + +envvars += $(shell sed -n '/^ENV:/{s/^ENV://;p}' $(OPT_FILE) 2>/dev/null) +makevars += $(patsubst %,-D%,$(shell sed -n '/^...:/!{s/ *\#.*$$//; /^$$/!p}' \ + $(OPT_FILE) 2>/dev/null)) + +makecmd = $(envvars) cmake -H. -B$(DIR) \ + $(if $(findstring $(generator),ninja),-GNinja,-G'Unix Makefiles') \ + $(if $(findstring $(verbose),true on 1),-DCMAKE_VERBOSE_MAKEFILE=true) \ + -DTOOLCHAIN=$(toolchain) \ + -DCMAKE_USER_MAKE_RULES_OVERRIDE=$(ROOT_DIR:%/=%)/build-aux/CMakeInit.txt \ + -DCMAKE_INSTALL_PREFIX=$(prefix) \ + -DCMAKE_BUILD_TYPE=$(build) $(makevars) + +#------------------------------------------------------------------------------- +# bootstrap target +#------------------------------------------------------------------------------- +bootstrap: | $(DIR) + ifeq "$(generator)" "" + @echo -e "\n\e[1;31mBuild tool not specified!\e[0m\n" && false + else ifeq "$(shell which $(generator) 2>/dev/null)" "" + @echo -e "\n\e[1;31mBuild tool $(generator) not found!\e[0m\n" && false + endif + @echo -e "Options file.....: $(OPT_FILE)" + @echo -e "Build directory..: \e[0;36m$(DIR)\e[0m" + @echo -e "Install directory: \e[0;36m$(prefix)\e[0m" + @echo -e "Build type.......: \e[1;32m$(BUILD)\e[0m" + @echo -e "Command-line vars: $(variables)" + @echo -e "\n-- \e[1;37mUsing $(generator) generator\e[0m\n" + @mkdir -p .build + @rm -f inst + @[ -L build ] && rm -f build || true + @echo $(call makecmd) > $(DIR)/.cmake + $(call makecmd) 2>&1 | tee $(DIR)/.cmake.bootstrap.log + @[ ! -d build ] && ln -s $(DIR) build || true + @ln -s $(prefix) inst + @echo "make bootstrap $(MAKEOVERRIDES)" > $(DIR)/.bootstrap + @cp $(DIR)/.bootstrap .build/ + @echo "PROJECT := $(PROJECT)" > $(DIR)/cache.mk + @echo "VERSION := $(VERSION)" >> $(DIR)/cache.mk + @echo "OPT_FILE := $(abspath $(OPT_FILE))" >> $(DIR)/cache.mk + @echo "generator := $(generator)" >> $(DIR)/cache.mk + @echo "build := $(BUILD)" >> $(DIR)/cache.mk + @echo "DIR := $(DIR)" >> $(DIR)/cache.mk + @echo "prefix := $(prefix)" >> $(DIR)/cache.mk + +$(DIR): + @mkdir -p $@ + +.PHONY: all bootstrap info diff --git a/build-aux/CMakeEx.txt b/build-aux/CMakeEx.txt new file mode 100644 index 0000000..00f69aa --- /dev/null +++ b/build-aux/CMakeEx.txt @@ -0,0 +1,69 @@ +#------------------------------------------------------------------------------- +# Colorization support +#------------------------------------------------------------------------------- +if(NOT WIN32) + string(ASCII 27 Esc) + string(CONCAT Esc ${Esc} "[") # So that vim highlighting doesn't get screwed + set(Red "${Esc}0;31m") + set(Green "${Esc}0;32m") + set(Yellow "${Esc}0;33m") + set(Blue "${Esc}0;34m") + set(Magenta "${Esc}0;35m") + set(Cyan "${Esc}0;36m") + set(White "${Esc}0;37m") + set(BoldRed "${Esc}1;31m") + set(BoldGreen "${Esc}1;32m") + set(BoldYellow "${Esc}1;33m") + set(BoldBlue "${Esc}1;34m") + set(BoldMagenta "${Esc}1;35m") + set(BoldCyan "${Esc}1;36m") + set(BoldWhite "${Esc}1;37m") + set(ClrBold "${Esc}1m") + set(ClrReset "${Esc}m") +endif() + +#------------------------------------------------------------------------------- +# File downloading function +#------------------------------------------------------------------------------- +function(download filename url) + if (NOT EXISTS ${filename}) + file(DOWNLOAD ${url} ${filename} + STATUS status LOG log ) + list(GET status 0 status_code) + list(GET status 1 status_string) + + if(NOT status_code EQUAL 0) + file(APPEND ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeOutput.log + "Failed to download ${url}\n" + " Reason: ${status_string}\n\n" + "${log}" + ) + message(FATAL_ERROR + "${Red}Failed to download ${url}${ClrReset}" + " Reason: ${status_string}" + ) + else() + message(STATUS "${ClrBold}Downloaded ${url}${ClrReset}") + message(STATUS "${ClrBold} -> ${filename}${ClrReset}") + endif() + endif() +endfunction(download) + +#------------------------------------------------------------------------------- +# prefix and suffix each element of list by ${prefix}elemnt${suffix} +#------------------------------------------------------------------------------- +macro(PREFIX list_name prefix) + # create empty list - necessary? + set(${list_name}_TMP) + + # prefix and suffix (optional 3rd parameter) elements + foreach(l ${${list_name}}) + list(APPEND ${list_name}_TMP ${prefix}${l}${ARGV3} ) + endforeach() + + # replace list by tmp list + set(${list_name} "${${list_name}_TMP}") + unset(${list_name}_TMP) +endmacro(PREFIX) + + diff --git a/build-aux/CMakeInit.txt b/build-aux/CMakeInit.txt new file mode 100644 index 0000000..5cca588 --- /dev/null +++ b/build-aux/CMakeInit.txt @@ -0,0 +1,11 @@ +SET (CMAKE_C_FLAGS_INIT "-Wall -std=c99") +SET (CMAKE_C_FLAGS_DEBUG_INIT "-g -O0") +SET (CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +SET (CMAKE_C_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") +SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g") + +SET (CMAKE_CXX_FLAGS_INIT "-Wall -std=c++14 -march=native -Wno-deprecated -Wno-deprecated-declarations") +SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g -O0") +SET (CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +SET (CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") +SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2 -g") diff --git a/build-aux/erlang.m4 b/build-aux/erlang.m4 deleted file mode 100644 index c1674c2..0000000 --- a/build-aux/erlang.m4 +++ /dev/null @@ -1,87 +0,0 @@ -dnl------------------------------------------------------------------- -dnl AC_ERLANG_SUBST_ERTS_VER -dnl------------------------------------------------------------------- -AC_DEFUN([AC_ERLANG_SUBST_ERTS_VER], - [AC_REQUIRE([AC_ERLANG_NEED_ERLC])[]dnl - AC_REQUIRE([AC_ERLANG_NEED_ERL])[]dnl - AC_CACHE_CHECK([for Erlang/OTP ERTS version], - [erlang_cv_erts_ver], - [AC_LANG_PUSH(Erlang)[]dnl - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([], [dnl - Version = erlang:system_info(version), - file:write_file("conftest.out", Version), - halt(0)])], - [erlang_cv_erts_ver=`cat conftest.out`], - [AC_MSG_FAILURE([test Erlang program execution failed])]) - AC_LANG_POP(Erlang)[]dnl - ]) - AC_SUBST([ERLANG_ERTS_VER], [$erlang_cv_erts_ver]) - ])# AC_ERLANG_SUBST_ERTS_VER - -dnl------------------------------------------------------------------- -dnl More functions to query Erlang environment. -dnl------------------------------------------------------------------- - -dnl ERLANG_CHECK_ERTS([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) -dnl Substitudes -dnl ERLANG_ERTS_DIR -dnl ERLANG_ERTS_VER -AC_DEFUN([ERLANG_CHECK_ERTS], -[ -AC_REQUIRE([AC_ERLANG_SUBST_ROOT_DIR])[]dnl -AC_CACHE_CHECK([for Erlang/OTP ERTS version], - [erlang_cv_erts_ver], - [ - AC_LANG_PUSH(Erlang)[]dnl - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([], [dnl - file:write_file("conftest.out", erlang:system_info(version)), - halt(0)])], - [erlang_cv_erts_ver=`cat conftest.out`], - [if test ! -f conftest.out; then - AC_MSG_FAILURE([test Erlang program execution failed]) - else - erlang_cv_erts_ver="not found" - fi]) - AC_LANG_POP(Erlang)[]dnl - ]) -AC_CACHE_CHECK([for Erlang/OTP ERTS directory], - [erlang_cv_erts_dir], - [ - erlang_cv_erts_dir="${ERLANG_ROOT_DIR}/erts-$erlang_cv_erts_ver" - erlang_cv_drv_include="${ERLANG_ROOT_DIR}/usr/include" - if test ! -d "$erlang_cv_erts_dir"; then - erlang_cv_erts_dir="${ERLANG_ROOT_DIR}/usr" - fi - ]) -AC_SUBST([ERLANG_ERTS_DIR], [$erlang_cv_erts_dir]) -AC_SUBST([ERLANG_ERTS_VER], [$erlang_cv_erts_ver]) -AC_SUBST([ERLANG_DRV_INCLUDE], [$erlang_cv_drv_include]) -AS_IF([test "$erlang_cv_erts_ver" = "not found"], [$2], [$1]) -]) - -dnl ERLANG_CHECK_RELEASE() -dnl Substitudes -dnl ERLANG_RELEASE -AC_DEFUN([ERLANG_CHECK_RELEASE], -[ -AC_REQUIRE([AC_ERLANG_SUBST_ROOT_DIR])[]dnl -AC_CACHE_CHECK([for Erlang/OTP release], - [erlang_cv_release], - [ - AC_LANG_PUSH(Erlang)[]dnl - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([], [dnl - file:write_file("conftest.out", erlang:system_info(otp_release)), - halt(0)])], - [erlang_cv_release=`cat conftest.out`], - [if test ! -f conftest.out; then - AC_MSG_FAILURE([test Erlang program execution failed]) - else - erlang_cv_release="not found" - fi]) - AC_LANG_POP(Erlang)[]dnl - ]) -AC_SUBST([ERLANG_RELEASE], [$erlang_cv_release]) -]) diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 045084c..0000000 --- a/configure.ac +++ /dev/null @@ -1,191 +0,0 @@ -# -*- Autoconf -*- - -AC_PREREQ([2.63]) -AC_INIT([eixx], [1.1], [BUG-REPORT-ADDRESS]) -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_MACRO_DIR([build-aux]) -AM_INIT_AUTOMAKE([foreign -Wall -Wno-portability]) -AC_CONFIG_HEADERS(config.h) -AX_PREFIX_CONFIG_H(include/eixx/config.h) - -AC_SUBST([eixxdir], [$libdir]) - -# Default prefix -AC_PREFIX_DEFAULT(`pwd`) -AC_SUBST([default_prefix], [${PWD}/install]) -test "$prefix" = "NONE" && prefix="$default_prefix" -test "$sysconfdir" = "\${prefix}/etc" && sysconfdir='../etc' -test "$scriptdir" = "" && scriptdir='../lib' - -# Options - -AC_ARG_VAR([ERLC_FLAGS], [general flags to prepend to ERLC_FLAGS]) - -ERLC_FLAGS="${ERLC_FLAGS} +debug_info" -# CXXFLAGS="${CXXFLAGS% } -MMD -Wall -fno-strict-aliasing -fpermissive -Wl,-V" -CXXFLAGS="${CXXFLAGS% } -MMD -Wall -Wno-unused-local-typedefs -fno-strict-aliasing" -CXXFLAGS+=" -Wno-deprecated-declarations -std=c++11 -DBOOST_SYSTEM_NO_DEPRECATED=1" - -AC_ARG_ENABLE(debug, - AC_HELP_STRING([--enable-debug],[enable debug [[default=no]]]), - [ if test "x$enable_debug" = "xyes" -o -z "x$enable_debug"; then - # CXXFLAGS="${CXXFLAGS% } -ggdb -O0 -Wall -fno-default-inline -fno-inline -fno-inline-functions" - CXXFLAGS="${CXXFLAGS% } -g -O0" - elif test "x$enable_debug" = "xno"; then - ERLC_FLAGS="${ERLC_FLAGS//+debug_info}" - fi - ], -) - -AC_ARG_ENABLE(optimize, - AC_HELP_STRING([--enable-optimize],[enable code optimization [[default=yes]]]), - [ if test "x$enable_optimize" = "xyes" ; then - CXXFLAGS="${CXXFLAGS% } -g -O3" - fi - ], -) - -AC_ARG_ENABLE(warnings, - AC_HELP_STRING([--enable-warnings],[enable Wall compiling [[default=yes]]]), - [ if test "x$enable_warnings" = "xyes" -o -z "$enable_warnings"; then - CXXFLAGS="${CXXFLAGS% } -Wall -Werror" - fi - ], -) - -AC_LANG_PUSH(C++) -AC_ARG_ENABLE(cxx11, - AC_HELP_STRING([--disable-cxx11],[disable c++11 standard [default=no]]), - [ if test "x${enable_cxx11}" != "xno" -a -z "${disable_cxx11}"; then - AX_CXX_COMPILE_STDCXX_11([noext], [optional]) - fi - ], - [ - AX_CXX_COMPILE_STDCXX_11([noext], [optional]) - ] -) - -AC_LANG_POP([C++]) - -# libtool -LT_INIT([disable-static]) - -# Checks for programs. -AC_PROG_CXX -AC_PROG_SED - -# Checks for libraries. - -AX_BOOST_BASE([1.49.0], [], [AC_MSG_ERROR("BOOST library version >= 1.49.0 not found!")]) -AX_BOOST_SYSTEM -AX_BOOST_ASIO -AX_BOOST_DATE_TIME -# workaround unexpected extra dependency on boost_system library (at least in 1.49) -LDFLAGS+=" $BOOST_LDFLAGS $BOOST_SYSTEM_LIB -Wl,-rpath=${BOOST_LDFLAGS#-L}" -AX_BOOST_THREAD -AX_BOOST_UNIT_TEST_FRAMEWORK - -# eixx requires md5 support -AX_LIB_CRYPTO([yes]) -AC_CHECK_HEADERS([openssl/md5.h]) - -# Checks for header files. -AC_CHECK_HEADERS([stdlib.h string.h sys/time.h]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_HEADER_STDBOOL -AC_C_INLINE -AC_TYPE_SIZE_T -AC_TYPE_UINT32_T -AC_TYPE_UINT64_T - -AC_CHECK_ALIGNOF([uint64_t]) -AC_CHECK_SIZEOF([long]) - -# Checks for library functions. -AC_CHECK_FUNCS([gettimeofday socket sqrt]) - -dnl ------------------------------------------------------------------ -dnl Erlang environment. -dnl ------------------------------------------------------------------ - -AC_MSG_NOTICE([Erlang environment]) - -dnl Check for erl_interface (used by port drivers). - -AC_ERLANG_CHECK_LIB([kernel],, - [AC_MSG_ERROR([kernel was not found!])]) -AC_ERLANG_CHECK_LIB([stdlib],, - [AC_MSG_ERROR([stdlib was not found!])]) -AC_ERLANG_CHECK_LIB([sasl],, - [AC_MSG_ERROR([sasl was not found!])]) -AC_ERLANG_CHECK_LIB([erl_interface],, - [AC_MSG_ERROR([erl_interface was not found!])]) - -AC_SUBST(ERL_CALL,[$ERLANG_LIB_DIR_erl_interface]/bin/erl_call) - -dnl Available flags. -AC_ARG_WITH([erlang], - AC_HELP_STRING([--with-erlang=PATH], - [PATH to Erlang installation (optional)]), - with_erlang=${withval%/}, - with_erlang="") - -dnl erl(1) is used to compile Erlang modules. -if test "x${with_erlang}" = "x"; then - AC_ERLANG_PATH_ERL - AC_ERLANG_PATH_ERLC - AC_ERLANG_SUBST_ROOT_DIR -else - erl_path="${with_erlang}/bin" - AC_ERLANG_PATH_ERL(, [$erl_path$PATH_SEPARATOR$PATH]) - AC_ERLANG_PATH_ERLC(, [$erl_path$PATH_SEPARATOR$PATH]) - AC_ERLANG_SUBST_ROOT_DIR -fi - -if test "x${ERL}" = "x"; then - AC_MSG_ERROR([ -Erlang not found. Fill the ERL variable with erl(1) path or provide -Erlang prefix with --with-erlang.]) -fi - -AC_SUBST([EI_LDFLAGS], ["-L${ERLANG_LIB_DIR_erl_interface}/lib"]) -AC_SUBST([EI_LIB], ["-lei"]) - -AC_CHECK_HEADERS([${ERLANG_LIB_DIR_erl_interface}/src/epmd/ei_epmd.h], - [ AC_DEFINE([HAVE_EI_EPMD], [1], - [erl_interface/src/epmd/ei_epmd.h is available]) - AC_SUBST([EI_CPPFLAGS], - ["-I${ERLANG_LIB_DIR_erl_interface}/include -I${ERLANG_LIB_DIR_erl_interface}/src"]) - ], - [ - AC_SUBST([EI_CPPFLAGS], - ["-I ${ERLANG_LIB_DIR_erl_interface}/include"]) - ]) - -dnl Get ERTS version. -ERLANG_CHECK_ERTS -ERLANG_CHECK_RELEASE -AC_ERLANG_SUBST_ERTS_VER - -dnl ------------------------------------------------------------------ -dnl Output. -dnl ------------------------------------------------------------------ - -AC_CONFIG_FILES([Makefile]) -AC_CONFIG_FILES([src/Makefile]) -AC_CONFIG_FILES([src/eixx.pc:src/eixx.pc.in]) -AC_CONFIG_FILES([test/Makefile]) - -AC_OUTPUT - -echo -echo "========================================================================" -echo " CXXFLAGS: ${CXXFLAGS}" $BOOST_CPPFLAGS -echo " LDFLAGS: ${LDFLAGS} ${EI_LDFLAGS}" -echo " BOOST: $BOOST_ROOT" -echo " Erlang: $ERLANG_ROOT_DIR" -echo "------------------------------------------------------------------------" -echo " Configuration completed successfully! " -echo "========================================================================" -echo diff --git a/eixx.kdev4 b/eixx.kdev4 new file mode 100644 index 0000000..c7bd927 --- /dev/null +++ b/eixx.kdev4 @@ -0,0 +1,3 @@ +[Project] +Manager=KDevCustomMakeManager +Name=eixx diff --git a/src/eixx.pc.in b/eixx.pc.in similarity index 100% rename from src/eixx.pc.in rename to eixx.pc.in diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index 0ff46d8..6976296 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -194,12 +194,12 @@ class basic_otp_mailbox * * The call is non-blocking. If returns Upon timeout * or delivery of a message to the mailbox the handler \a h will be - * invoked. The handler must have a signature with two arguments: - * \verbatim + * invoked. The handler must have a signature with three arguments: + * \code * void handler(basic_otp_mailbox& a_mailbox, - * transport_msg*& a_msg, - * ::boost::system::error_code& a_errc); - * \endverbatim + * transport_msg*& a_msg, + * ::boost::system::error_code& a_err); + * \endcode * In case of timeout the error will be set to non-zero value * * @param h is the handler to call upon arrival of a message @@ -207,11 +207,14 @@ class basic_otp_mailbox * @param a_repeat_count is the number of messages to wait (-1 = infinite) * @return true if the message was synchronously received **/ - bool async_receive(receive_handler_type h, - std::chrono::milliseconds a_timeout = std::chrono::milliseconds(-1), - int a_repeat_count = 0 - ) - throw (std::runtime_error); + template + bool async_receive + ( + const OnReceive& h, + std::chrono::milliseconds a_timeout = std::chrono::milliseconds(-1), + int a_repeat_count = 0 + ) + throw (std::runtime_error); /** * Cancel pending asynchronous receive operation @@ -222,12 +225,24 @@ class basic_otp_mailbox /** * Wait for messages and perform pattern match when a message arives + * + * @param a_matcher is the pattern matcher to run + * @param a_on_timeout is the callback to be executed on timeout. It should + * have the following signature + * \code + * void on_timeout(basic_otp_mailbox&); + * \endcode + * @param a_repeat_count number of messages to wait (-1 = infinite) */ - bool async_match(const marshal::eterm_pattern_matcher& a_matcher, - const std::function&)>& a_on_timeout, - std::chrono::milliseconds a_timeout = std::chrono::milliseconds(-1), - int a_repeat_count = 0) - throw (std::runtime_error); + template + bool async_match + ( + const marshal::eterm_pattern_matcher& a_matcher, + const OnTimeout& a_on_timeout, + std::chrono::milliseconds a_timeout = std::chrono::milliseconds(-1), + int a_repeat_count = 0 + ) + throw (std::runtime_error); /// Deliver a message to this mailbox. The call is thread-safe. void deliver(const transport_msg& a_msg) { diff --git a/include/eixx/connect/basic_otp_mailbox.ipp b/include/eixx/connect/basic_otp_mailbox.ipp index 52bd29f..bcb5f40 100644 --- a/include/eixx/connect/basic_otp_mailbox.ipp +++ b/include/eixx/connect/basic_otp_mailbox.ipp @@ -52,12 +52,13 @@ close(const eterm& a_reason, bool a_reg_remove) { } template +template bool basic_otp_mailbox:: -async_receive(receive_handler_type h, std::chrono::milliseconds a_timeout, - int a_repeat_count) throw (std::runtime_error) +async_receive(const OnReceive& h, std::chrono::milliseconds a_timeout, + int a_repeat_count) throw (std::runtime_error) { return m_queue->async_dequeue( - [this, h](transport_msg*& a_msg, const boost::system::error_code& ec) { + [this, &h](transport_msg*& a_msg, const boost::system::error_code& ec) { if (this->m_time_freed.time_since_epoch().count() == 0 || !h) return false; bool res; @@ -79,14 +80,15 @@ async_receive(receive_handler_type h, std::chrono::milliseconds a_timeout, } template +template bool basic_otp_mailbox:: async_match(const marshal::eterm_pattern_matcher& a_matcher, - const std::function&)>& a_on_timeout, + const OnTimeout& a_on_timeout, std::chrono::milliseconds a_timeout, int a_repeat_count) throw (std::runtime_error) { auto f = - [this, &a_matcher, a_on_timeout] + [this, &a_matcher, &a_on_timeout] (transport_msg*& a_msg, const boost::system::error_code& ec) { if (this->m_time_freed.time_since_epoch().count() == 0) return false; @@ -116,7 +118,8 @@ break_links(const eterm& a_reason) try { m_node.send_exit(self(), *it, a_reason); } catch(...) {} for (typename std::map, epid >::const_iterator it = m_monitors.begin(), end = m_monitors.end(); it != end; ++it) - try { m_node.send_monitor_exit(self(), it->second, it->first, a_reason); } catch(...) {} + try { m_node.send_monitor_exit(self(), it->second, it->first, a_reason); } + catch(...) {} if (!m_links.empty()) m_links.clear(); if (!m_monitors.empty()) m_monitors.clear(); } diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index dc512a2..9cdaaee 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -29,8 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***** END LICENSE BLOCK ***** */ -#ifndef _EIXX_ASYNC_QUEUE_HPP -#define _EIXX_ASYNC_QUEUE_HPP +#pragma once #include #include @@ -122,7 +121,7 @@ struct async_queue : std::enable_shared_from_this> } // Called by io_service on timeout of m_timer - void operator() (const async_handler& h, const boost::system::error_code& ec, + void operator() (async_handler h, const boost::system::error_code& ec, std::chrono::milliseconds repeat, int repeat_count) { process_queue(h, ec, repeat, repeat_count); } @@ -214,9 +213,7 @@ struct async_queue : std::enable_shared_from_this> m_timer.async_wait( [this, &a_on_data, timeout, rep] (const boost::system::error_code& e) { - auto p = this->shared_from_this(); - if (p) - (*p)(a_on_data, e, timeout, rep); + (*this->shared_from_this())(a_on_data, e, timeout, rep); } ); } @@ -226,6 +223,4 @@ struct async_queue : std::enable_shared_from_this> }; } // namespace util -} // namespace EIXX_NAMESPACE - -#endif // _EIXX_ASYNC_QUEUE_HPP +} // namespace EIXX_NAMESPACE \ No newline at end of file diff --git a/license.sh b/license.sh index efd5e54..067f0d7 100644 --- a/license.sh +++ b/license.sh @@ -1,4 +1,8 @@ for f in $(find include -name '*.?pp') $(find src -name '*.cpp'); do - awk 'BEGIN {m=1} /BEGIN LICENSE BLOCK/ {m=0; print $0; while (getline < "LICENSE.header") print} ' \ - '/END LICENSE BLOCK/ {m=1} m {print $0}' $f > t && mv -v t $f + echo "Processing $f" + gawk -i inplace ' + BEGIN {m=1} + /BEGIN LICENSE BLOCK/ {m=0; print $0; while (getline < "LICENSE.header") print} + /END LICENSE BLOCK/ {m=1} m {print $0} + ' $f done diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..625d85a --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,30 @@ +# vim:ts=2:sw=2:et + +list(APPEND EIXX_SRCS + am.cpp + basic_otp_node_local.cpp + test_node.cpp +) + +add_library(${PROJECT_NAME} SHARED ${EIXX_SRCS}) +add_library(${PROJECT_NAME}_static STATIC ${EIXX_SRCS}) +set_target_properties(${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) +target_link_libraries(${PROJECT_NAME} ${EIXX_LIBS}) + +if (${BUILD_TYPE} STREQUAL "Debug") + set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX "-d.so") + set_target_properties(${PROJECT_NAME}_static PROPERTIES SUFFIX "-d.so") +endif() + +set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) + +add_executable(test-node test_node.cpp) +target_link_libraries(test-node utxx) +target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) + +install( + TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_static test-node + RUNTIME DESTINATION test + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) diff --git a/src/test_node.cpp b/src/test_node.cpp index b7fa7dd..682bd76 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -25,7 +25,9 @@ void on_status(otp_node& a_node, const otp_connection* a_con, std::cerr << s_levels[a_level] << "| " << s << std::endl; } -otp_mailbox *g_io_server, *g_main; +std::shared_ptr g_io_server; +std::shared_ptr g_main; + static atom g_rem_node; static const atom S = atom("S"); @@ -106,15 +108,15 @@ int main(int argc, char* argv[]) { if (argc < 2) usage(argv[0]); - const char* l_nodename = NULL, *l_remote = NULL, *use_cookie = ""; + const char* nodename = NULL, *remote = NULL, *use_cookie = ""; connect::verbose_type verbose = connect::verboseness::level(); int reconnect_secs = 0; for (int i = 1; i < argc && argv[i][0] == '-'; i++) { if (strcmp(argv[i], "-n") == 0 && i < argc-1) - l_nodename = argv[++i]; + nodename = argv[++i]; else if (strcmp(argv[i], "-r") == 0 && i < argc-1) - l_remote = argv[++i]; + remote = argv[++i]; else if (strcmp(argv[i], "-c") == 0 && i < argc-1) use_cookie = argv[++i]; else if (strcmp(argv[i], "-v") == 0 && i < argc-1) @@ -125,29 +127,41 @@ int main(int argc, char* argv[]) { usage(argv[0]); } - if (!l_nodename || !l_remote) + if (!nodename || !remote) usage(argv[0]); boost::asio::io_service io_service; - otp_node l_node(io_service, l_nodename, use_cookie); - l_node.verbose(verbose); - l_node.on_status = on_status; - l_node.on_disconnect = on_disconnect; + otp_node node(io_service, nodename, use_cookie); + node.verbose(verbose); + node.on_status = on_status; + node.on_disconnect = on_disconnect; + + g_io_server.reset(node.create_mailbox("io_server")); + g_main .reset(node.create_mailbox("main")); + g_rem_node = atom(remote); + + node.connect(on_connect, g_rem_node, reconnect_secs); - g_io_server = l_node.create_mailbox("io_server"); - g_main = l_node.create_mailbox("main"); - g_rem_node = atom(l_remote); + auto on_msg1 = [](auto& a_mailbox, auto& a_msg, + ::boost::system::error_code& a_err) + { + on_io_request(a_mailbox, a_msg); + }; - l_node.connect(&on_connect, g_rem_node, reconnect_secs); + auto on_msg2 = [](auto& a_mailbox, auto& a_msg, + ::boost::system::error_code& a_err) + { + on_main_msg(a_mailbox, a_msg); + }; - //otp_connection::connection_type* l_transport = a_con->transport(); - g_io_server->async_receive(on_io_request, std::chrono::milliseconds(-1), -1); + //otp_connection::connection_type* transport = a_con->transport(); + g_io_server->async_receive(on_msg1, std::chrono::milliseconds(-1), -1); - //l_node->send_rpc(self, a_con->remote_node(), atom("shell_default"), atom("ls"), + //node->send_rpc(self, a_con->remote_node(), atom("shell_default"), atom("ls"), // list::make(), &io_server); - g_main->async_receive(on_main_msg, std::chrono::seconds(5), -1); + g_main->async_receive(on_msg2, std::chrono::seconds(5), -1); - l_node.run(); + node.run(); return 0; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..ffa04dc --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,42 @@ +# vim:ts=2:sw=2:et + +list(APPEND TEST_SRCS + test_eterm.cpp + test_eterm_encode.cpp + test_eterm_format.cpp + test_eterm_match.cpp + test_eterm_pool.cpp + test_eterm_refc.cpp + test_mailbox.cpp + test_node.cpp +) + +# This must be AFTER link_directories +add_executable(test-eterm ${TEST_SRCS}) +target_compile_definitions(test-eterm PRIVATE -DBOOST_TEST_DYN_LINK) +target_include_directories(test-eterm PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries( + test-eterm + eixx ei + boost_unit_test_framework + boost_system + boost_thread +) + +add_executable(test-connect test_async_queue.cpp) +target_link_libraries( + test-connect + eixx + boost_unit_test_framework + boost_system + boost_thread +) + +add_executable(test-perf test_perf.cpp) +target_link_libraries( + test-perf + eixx ei + boost_system +) + +install(TARGETS test-eterm test-connect test-perf RUNTIME DESTINATION test) From 52f7658659ef64074faea941016db1b2eedf1338 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sat, 16 Jan 2016 23:25:22 -0500 Subject: [PATCH 068/185] Fix build --- CMakeLists.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 591ce56..72a5f01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,6 +102,7 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # Dependent packages and their directory locations #------------------------------------------------------------------------------- find_package(PkgConfig) +find_program(ERL erl) set(PKG_ROOT_DIR "/opt/pkg" CACHE STRING "Package root directory") @@ -136,6 +137,18 @@ set(Boost_LIBRARIES ${Boost_IOSTREAMS_LIBRARY} ) +execute_process( + COMMAND ${ERL} -eval "io:format(\"~s\", [code:root_dir()]), halt()." + -noshell -noinput + OUTPUT_VARIABLE Erl_DIR +) +execute_process( + COMMAND ${ERL} -eval "io:format(\"~s\", [code:lib_dir(erl_interface)]), halt()." + -noshell -noinput + OUTPUT_VARIABLE Erl_ERL_INTERFACE_DIR +) +message(STATUS "Erl interface: ${Erl_ERL_INTERFACE_DIR}") + set(AddCleanFiles) # Additional clean files #------------------------------------------------------------------------------- @@ -149,6 +162,8 @@ set(AddCleanFiles) # Additional clean files include_directories( SYSTEM ${Boost_INCLUDE_DIRS} + ${Erl_DIR}/usr/include + ${Erl_ERL_INTERFACE_DIR}/src ) include_directories( ${CMAKE_SOURCE_DIR}/include @@ -156,6 +171,7 @@ include_directories( ) link_directories( ${Boost_LIBRARY_DIRS} + ${Erl_DIR}/usr/lib ) #------------------------------------------------------------------------------- From 75c53710531589939196fd9cf4cacf93a3c8f167 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 00:23:33 -0500 Subject: [PATCH 069/185] Fix build issues --- .gitignore | 43 -------- CMakeLists.txt | 35 ++++--- Makefile | 55 +++++++++++ build-aux/install-symlinks.cmake | 11 +++ config.h.in | 3 + include/eixx/connect/basic_otp_mailbox.ipp | 2 +- src/CMakeLists.txt | 12 ++- src/Makefile.am | 108 --------------------- src/test_node.cpp | 10 +- test/CMakeLists.txt | 6 +- test/Makefile.am | 32 ------ 11 files changed, 110 insertions(+), 207 deletions(-) create mode 100644 Makefile create mode 100644 build-aux/install-symlinks.cmake create mode 100644 config.h.in delete mode 100644 src/Makefile.am delete mode 100644 test/Makefile.am diff --git a/.gitignore b/.gitignore index a6263ca..bb64e26 100644 --- a/.gitignore +++ b/.gitignore @@ -1,48 +1,5 @@ *.swp *.dump -stamp-h1 -eixx*.tar.gz -aclocal.m4 -autom4te.cache/ -build-aux/config.guess -build-aux/config.sub -build-aux/depcomp -build-aux/install-sh -build-aux/libtool.m4 -build-aux/ltmain.sh -build-aux/ltoptions.m4 -build-aux/ltsugar.m4 -build-aux/ltversion.m4 -build-aux/lt~obsolete.m4 -build-aux/missing -_configs.sed -config.h -include/eixx/config.h -config.h.in* -config.log -config.status -configure -libtool -Makefile -Makefile.in -src/.deps -src/.libs -src/Makefile -src/Makefile.in -src/eixx.pc -src/pri_test -src/test_node -src/*.la -src/*.lo -src/*.o -test/.deps -test/.libs -test/Makefile -test/Makefile.in -test/test_eterm -test/*.o -test/test_perf -test/test_connect .build/ .cproject .kdev4/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 72a5f01..10a5ae6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,23 +86,12 @@ set(CMAKE_INSTALL_RPATH "${CMAKE_BINARY_DIR}/src:${CMAKE_INSTALL_PREFIX}/lib") # which point to directories outside the build tree to the install RPATH set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) -#------------------------------------------------------------------------------- -# Platform-specific checks -#------------------------------------------------------------------------------- -#include(${CMAKE_ROOT}/Modules/CheckTypeSize.cmake) -#include(${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake) -#include(${CMAKE_ROOT}/Modules/CheckStructHasMember.cmake) -#include(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) - -#CHECK_INCLUDE_FILE(netinet/in.h HAVE_NETINET_IN_H) -# Needed for pcap.hpp tests -#CHECK_STRUCT_HAS_MEMBER("struct tcphdr" th_flags netinet/tcp.h UTXX_HAVE_TCPHDR_TH_FLAGS_H) - #------------------------------------------------------------------------------- # Dependent packages and their directory locations #------------------------------------------------------------------------------- find_package(PkgConfig) find_program(ERL erl) +find_package(OpenSSL REQUIRED) set(PKG_ROOT_DIR "/opt/pkg" CACHE STRING "Package root directory") @@ -162,6 +151,7 @@ set(AddCleanFiles) # Additional clean files include_directories( SYSTEM ${Boost_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIR} ${Erl_DIR}/usr/include ${Erl_ERL_INTERFACE_DIR}/src ) @@ -174,6 +164,25 @@ link_directories( ${Erl_DIR}/usr/lib ) +set(EIXX_LIBS + ei + ${OPENSSL_LIBRARIES} # For MD5 support + pthread +) + +#------------------------------------------------------------------------------- +# Platform-specific checks +#------------------------------------------------------------------------------- +#include(${CMAKE_ROOT}/Modules/CheckTypeSize.cmake) +#include(${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake) +#include(${CMAKE_ROOT}/Modules/CheckStructHasMember.cmake) +include(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) + +set(CMAKE_REQUIRED_INCLUDES ${Erl_ERL_INTERFACE_DIR}/src) +CHECK_INCLUDE_FILE(epmd/ei_epmd.h HAVE_EI_EPMD) +# Needed for pcap.hpp tests +#CHECK_STRUCT_HAS_MEMBER("struct tcphdr" th_flags netinet/tcp.h UTXX_HAVE_TCPHDR_TH_FLAGS_H) + #------------------------------------------------------------------------------- # Configure files #------------------------------------------------------------------------------- @@ -228,7 +237,7 @@ set_directory_properties( #=============================================================================== enable_testing() -add_test(test-utxx test/test-eixx -l message) +add_test(test-eixx test/test-eterm -l message) #=============================================================================== # Documentation options diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e777e13 --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +# vim:ts=4:sw=4:et +#------------------------------------------------------------------------------- +# Makefile helper for cmake +#------------------------------------------------------------------------------- +# Copyright (c) 2015 Serge Aleynikov +# Date: 2014-08-12 +#------------------------------------------------------------------------------- + +build ?= debug +BUILD_ARG := $(shell echo $(build) | tr 'A-Z' 'a-z') +REBOOSTR_FILE := .build/.bootstrap + +-include build/cache.mk + +VERBOSE := $(if $(findstring $(verbose),true 1),$(if $(findstring $(generator),ninja),-v,VERBOSE=1)) + +.DEFAULT_GOAL := all + +distclean: + @[ -n "$(DIR)" -a -d "$(DIR)" ] && echo "Removing $(DIR)" && rm -fr $(DIR) build inst || true + +bootstrap: + @$(MAKE) -f bootstrap.mk --no-print-directory $@ $(MAKEOVERRIDES) + +rebootstrap: .build/.bootstrap + $(if $(build),$(filter-out build=%,$(shell cat $(REBOOSTR_FILE))) \ + build=$(BUILD_ARG),$(shell cat $(REBOOSTR_FILE))) --no-print-directory $(MAKEOVERRIDES) + +test: + CTEST_OUTPUT_ON_FAILURE=TRUE $(generator) -C$(DIR) $(VERBOSE) -j$(shell nproc) $@ + +info: + @$(MAKE) -sf bootstrap.mk --no-print-directory $@ + +vars: + @cmake -H. -B$(DIR) -LA + +tree: + @tree build -I "*.cmake|CMake*" --matchdirs -F -a $(if $(full),-f) + +build/cache.mk: + +.build/.bootstrap: + @echo "Rerun 'make bootstrap'!" && false + +.DEFAULT: + @if [ ! -f build/cache.mk ]; then \ + $(MAKE) -f bootstrap.mk --no-print-directory; \ + else \ + $(generator) -C$(DIR) $(VERBOSE)\ + $(if $(findstring $(generator),ninja),, --no-print-directory)\ + -j$(shell nproc) $@;\ + fi + +.PHONY: bootstrap rebootstrap distclean info test doc diff --git a/build-aux/install-symlinks.cmake b/build-aux/install-symlinks.cmake new file mode 100644 index 0000000..451293b --- /dev/null +++ b/build-aux/install-symlinks.cmake @@ -0,0 +1,11 @@ +# vim:ts=2:sw=2:et + +if(CMAKE_HOST_UNIX) + get_filename_component(Dir ${CMAKE_INSTALL_PREFIX} DIRECTORY) + message(STATUS "Symlink: ${Dir}/current -> ${CMAKE_INSTALL_PREFIX}") + + execute_process( + COMMAND rm -f ${Dir}/current + COMMAND ln -s ${CMAKE_INSTALL_PREFIX} ${Dir}/current + ) +endif() diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..70ae4ed --- /dev/null +++ b/config.h.in @@ -0,0 +1,3 @@ +/* erl_interface/src/epmd/ei_epmd.h is available */ +#cmakedefine HAVE_EI_EPMD + diff --git a/include/eixx/connect/basic_otp_mailbox.ipp b/include/eixx/connect/basic_otp_mailbox.ipp index bcb5f40..6d8d67c 100644 --- a/include/eixx/connect/basic_otp_mailbox.ipp +++ b/include/eixx/connect/basic_otp_mailbox.ipp @@ -59,7 +59,7 @@ async_receive(const OnReceive& h, std::chrono::milliseconds a_timeout, { return m_queue->async_dequeue( [this, &h](transport_msg*& a_msg, const boost::system::error_code& ec) { - if (this->m_time_freed.time_since_epoch().count() == 0 || !h) + if (this->m_time_freed.time_since_epoch().count() == 0) return false; bool res; if (ec) { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 625d85a..db3a30e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,12 +19,18 @@ endif() set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) add_executable(test-node test_node.cpp) -target_link_libraries(test-node utxx) target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) +target_link_libraries(test-node eixx pthread) install( - TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_static test-node - RUNTIME DESTINATION test + TARGETS + ${PROJECT_NAME} + ${PROJECT_NAME}_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) +install( + TARGETS + test-node + RUNTIME DESTINATION test +) diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 3207c0b..0000000 --- a/src/Makefile.am +++ /dev/null @@ -1,108 +0,0 @@ -# vim:tw=2 tw=2 -# - -eixx_LTLIBRARIES = libeixx.la -bin_PROGRAMS = test_node - -eixx_hdrs1 = alloc_pool.hpp \ - alloc_pool_st.hpp \ - alloc_std_debug.hpp \ - alloc_std.hpp \ - config.h \ - connect.hpp \ - eixx.hpp \ - eterm.hpp \ - eterm_exception.hpp \ - namespace.hpp -eixx_hdrs2 = connect/basic_otp_connection.hpp \ - connect/basic_otp_mailbox.hpp \ - connect/basic_otp_mailbox.ipp \ - connect/basic_otp_mailbox_registry.hpp \ - connect/basic_otp_mailbox_registry.ipp \ - connect/basic_otp_node.hpp \ - connect/basic_otp_node.ipp \ - connect/basic_otp_node_local.hpp \ - connect/test_helper.hpp \ - connect/transport_msg.hpp \ - connect/transport_otp_connection.hpp \ - connect/transport_otp_connection.ipp \ - connect/transport_otp_connection_tcp.hpp \ - connect/transport_otp_connection_tcp.ipp \ - connect/transport_otp_connection_uds.hpp \ - connect/verbose.hpp -eixx_hdrs3 = marshal/alloc_base.hpp \ - marshal/am.hpp \ - marshal/atom.hpp \ - marshal/binary.hpp \ - marshal/binary.ipp \ - marshal/defaults.hpp \ - marshal/endian.hpp \ - marshal/eterm_format.hpp \ - marshal/eterm_format.ipp \ - marshal/eterm.hpp \ - marshal/eterm.ipp \ - marshal/eterm_match.hpp \ - marshal/list.hpp \ - marshal/list.ipp \ - marshal/pid.hpp \ - marshal/pid.ipp \ - marshal/port.hpp \ - marshal/port.ipp \ - marshal/ref.hpp \ - marshal/ref.ipp \ - marshal/string.hpp \ - marshal/trace.hpp \ - marshal/tuple.hpp \ - marshal/tuple.ipp \ - marshal/varbind.hpp \ - marshal/var.hpp \ - marshal/visit_encoder.hpp \ - marshal/visit_encode_size.hpp \ - marshal/visit.hpp \ - marshal/visit_match.hpp \ - marshal/visit_subst.hpp \ - marshal/visit_to_string.hpp -eixx_hdrs4 = util/async_queue.hpp \ - util/async_wait_timeout.hpp \ - util/atom_table.hpp \ - util/common.hpp \ - util/compiler_hints.hpp \ - util/hashtable.hpp \ - util/string_util.hpp \ - util/sync.hpp \ - util/timeout.hpp -eixx_hdrs5 = connect/detail/basic_rpc_server.hpp - -eixx_headers= $(eixx_hdrs1) \ - $(eixx_hdrs2) \ - $(eixx_hdrs3) \ - $(eixx_hdrs4) - -libeixx_la_hdr1dir = $(includedir)/@PACKAGE@ -libeixx_la_hdr1_HEADERS = $(eixx_hdrs1:%=../include/@PACKAGE@/%) -libeixx_la_hdr2dir = $(includedir)/@PACKAGE@/connect -libeixx_la_hdr2_HEADERS = $(eixx_hdrs2:%=../include/@PACKAGE@/%) -libeixx_la_hdr3dir = $(includedir)/@PACKAGE@/marshal -libeixx_la_hdr3_HEADERS = $(eixx_hdrs3:%=../include/@PACKAGE@/%) -libeixx_la_hdr4dir = $(includedir)/@PACKAGE@/util -libeixx_la_hdr4_HEADERS = $(eixx_hdrs4:%=../include/@PACKAGE@/%) -libeixx_la_hdr5dir = $(includedir)/@PACKAGE@/connect/detail -libeixx_la_hdr5_HEADERS = $(eixx_hdrs5:%=../include/@PACKAGE@/%) - -libeixx_la_SOURCES = am.cpp \ - basic_otp_node_local.cpp \ - $(eixx_headers:%=../include/@PACKAGE@/%) -libeixx_la_LTADD = -version-info 1:1:0 -shared -libeixx_la_LIBS = $(BOOST_THREAD_LIB) $(CRYPTO_LIBS) -libeixx_la_CXXFLAGS = $(if $(tr1),-std=c++0x) \ - -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ - -I../include $(BOOST_CPPFLAGS) \ - $(EI_CPPFLAGS) - -#EXTRA_DIST = ../README overview.inl overview_usage.inl overview_config.inl - -test_node_SOURCES = test_node.cpp -test_node_CPPFLAGS = -g -O0 -I$(srcdir)/../include $(BOOST_CPPFLAGS) $(EI_CPPFLAGS) -test_node_LDFLAGS = $(BOOST_LDFLAGS) $(EI_LDFLAGS) -test_node_LDADD = libeixx.la $(EI_LIB) \ - $(BOOST_SYSTEM_LIB) $(BOOST_THREAD_LIB) $(CRYPTO_LIBS) diff --git a/src/test_node.cpp b/src/test_node.cpp index 682bd76..c896c6f 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -142,16 +142,14 @@ int main(int argc, char* argv[]) { node.connect(on_connect, g_rem_node, reconnect_secs); - auto on_msg1 = [](auto& a_mailbox, auto& a_msg, - ::boost::system::error_code& a_err) + auto on_msg1 = [](auto& a_mailbox, auto& a_msg) { - on_io_request(a_mailbox, a_msg); + return on_io_request(a_mailbox, a_msg); }; - auto on_msg2 = [](auto& a_mailbox, auto& a_msg, - ::boost::system::error_code& a_err) + auto on_msg2 = [](auto& a_mailbox, auto& a_msg) { - on_main_msg(a_mailbox, a_msg); + return on_main_msg(a_mailbox, a_msg); }; //otp_connection::connection_type* transport = a_con->transport(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ffa04dc..c5ee9cb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -39,4 +39,8 @@ target_link_libraries( boost_system ) -install(TARGETS test-eterm test-connect test-perf RUNTIME DESTINATION test) +install( + TARGETS + test-eterm test-connect test-perf + RUNTIME DESTINATION test +) diff --git a/test/Makefile.am b/test/Makefile.am deleted file mode 100644 index 6efc669..0000000 --- a/test/Makefile.am +++ /dev/null @@ -1,32 +0,0 @@ -bin_PROGRAMS = test_eterm test_perf test_connect - -AM_CXXFLAGS = -I. -I$(srcdir)/../include $(BOOST_CPPFLAGS) \ - -I$(ERLANG_LIB_DIR_erl_interface)/include \ - -I$(ERLANG_LIB_DIR_erl_interface)/src - -test_eterm_SOURCES = test_eterm.cpp test_eterm_encode.cpp \ - test_eterm_format.cpp test_eterm_match.cpp \ - test_eterm_pool.cpp test_eterm_refc.cpp \ - test_mailbox.cpp test_node.cpp -test_eterm_CPPFLAGS = -DBOOST_TEST_DYN_LINK -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ - $(if $(debug),-DEIXX_DEBUG) -test_eterm_LDFLAGS = $(BOOST_LDFLAGS) \ - -L$(ERLANG_LIB_DIR_erl_interface)/lib -test_eterm_LDADD = -L../src/.libs -leixx -lei \ - $(BOOST_SYSTEM_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) \ - $(BOOST_THREAD_LIB) - -test_connect_SOURCES = test_async_queue.cpp -test_connect_CPPFLAGS = -DBOOST_TEST_DYN_LINK -g -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) \ - $(if $(debug),-DEIXX_DEBUG) -test_connect_LDFLAGS = $(BOOST_LDFLAGS) -test_connect_LDADD = -L../src/.libs -leixx \ - $(BOOST_SYSTEM_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) \ - $(BOOST_THREAD_LIB) - -test_perf_SOURCES = test_perf.cpp -test_perf_CPPFLAGS = -O$(if $(optimize),3 -DBOOST_DISABLE_ASSERTS,0) -Wno-unused-variable -test_perf_LDFLAGS = -L$(ERLANG_LIB_DIR_erl_interface)/lib $(BOOST_LDFLAGS) -test_perf_LDADD = -L../src/.libs -leixx -lei $(BOOST_SYSTEM_LIB) - - From 12869eec5db34337ba3085f46ceb788fadeae524 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 00:45:38 -0500 Subject: [PATCH 070/185] Remove EIXX_NAMESPACE macro --- Makefile | 2 +- build-aux/Doxyfile.in | 11 ++++-- config.h.in | 2 +- include/eixx/alloc_pool.hpp | 5 +-- include/eixx/alloc_pool_st.hpp | 5 +-- include/eixx/alloc_std.hpp | 5 +-- include/eixx/alloc_std_debug.hpp | 5 +-- include/eixx/connect.hpp | 4 +- include/eixx/connect/basic_otp_connection.hpp | 4 +- include/eixx/connect/basic_otp_mailbox.hpp | 14 +++---- include/eixx/connect/basic_otp_mailbox.ipp | 4 +- .../connect/basic_otp_mailbox_registry.hpp | 4 +- .../connect/basic_otp_mailbox_registry.ipp | 4 +- include/eixx/connect/basic_otp_node.hpp | 8 ++-- include/eixx/connect/basic_otp_node.ipp | 4 +- include/eixx/connect/basic_otp_node_local.hpp | 4 +- .../eixx/connect/detail/basic_rpc_server.hpp | 4 +- include/eixx/connect/test_helper.hpp | 4 +- include/eixx/connect/transport_msg.hpp | 20 +++++----- .../eixx/connect/transport_otp_connection.hpp | 4 +- .../eixx/connect/transport_otp_connection.ipp | 6 +-- .../connect/transport_otp_connection_tcp.hpp | 4 +- .../connect/transport_otp_connection_tcp.ipp | 4 +- .../connect/transport_otp_connection_uds.hpp | 4 +- include/eixx/connect/verbose.hpp | 4 +- include/eixx/eterm.hpp | 5 +-- include/eixx/eterm_exception.hpp | 4 +- include/eixx/marshal/alloc_base.hpp | 4 +- include/eixx/marshal/am.hpp | 4 +- include/eixx/marshal/atom.hpp | 8 ++-- include/eixx/marshal/binary.hpp | 8 ++-- include/eixx/marshal/binary.ipp | 4 +- include/eixx/marshal/defaults.hpp | 5 +-- .../marshal/detail/array_variadic_init.hpp | 4 +- include/eixx/marshal/endian.hpp | 4 +- include/eixx/marshal/eterm.hpp | 6 +-- include/eixx/marshal/eterm.ipp | 4 +- include/eixx/marshal/eterm_format.hpp | 4 +- include/eixx/marshal/eterm_format.ipp | 4 +- include/eixx/marshal/eterm_match.hpp | 4 +- include/eixx/marshal/list.hpp | 6 +-- include/eixx/marshal/list.ipp | 4 +- include/eixx/marshal/pid.hpp | 6 +-- include/eixx/marshal/pid.ipp | 4 +- include/eixx/marshal/port.hpp | 6 +-- include/eixx/marshal/port.ipp | 4 +- include/eixx/marshal/ref.hpp | 6 +-- include/eixx/marshal/ref.ipp | 4 +- include/eixx/marshal/string.hpp | 12 +++--- include/eixx/marshal/trace.hpp | 6 +-- include/eixx/marshal/tuple.hpp | 6 +-- include/eixx/marshal/tuple.ipp | 4 +- include/eixx/marshal/var.hpp | 8 ++-- include/eixx/marshal/varbind.hpp | 8 ++-- include/eixx/marshal/visit.hpp | 4 +- include/eixx/marshal/visit_encode_size.hpp | 6 +-- include/eixx/marshal/visit_encoder.hpp | 4 +- include/eixx/marshal/visit_match.hpp | 6 +-- include/eixx/marshal/visit_subst.hpp | 6 +-- include/eixx/marshal/visit_to_string.hpp | 4 +- include/eixx/namespace.hpp | 39 ------------------- include/eixx/util/async_queue.hpp | 5 +-- include/eixx/util/atom_table.hpp | 6 +-- include/eixx/util/common.hpp | 8 ++-- include/eixx/util/compiler_hints.hpp | 4 +- include/eixx/util/hashtable.hpp | 4 +- include/eixx/util/string_util.hpp | 4 +- include/eixx/util/sync.hpp | 4 +- src/am.cpp | 4 +- src/basic_otp_node_local.cpp | 4 +- src/server.hpp | 9 ++--- src/test_node.cpp | 2 +- test/test_eterm_format.cpp | 2 +- test/test_eterm_match.cpp | 2 +- test/test_eterm_pool.cpp | 2 +- test/test_eterm_refc.cpp | 4 +- test/test_perf.cpp | 2 +- 77 files changed, 192 insertions(+), 238 deletions(-) delete mode 100644 include/eixx/namespace.hpp diff --git a/Makefile b/Makefile index e777e13..b7fc217 100644 --- a/Makefile +++ b/Makefile @@ -52,4 +52,4 @@ build/cache.mk: -j$(shell nproc) $@;\ fi -.PHONY: bootstrap rebootstrap distclean info test doc +.PHONY: bootstrap rebootstrap distclean info test diff --git a/build-aux/Doxyfile.in b/build-aux/Doxyfile.in index f1510c9..38dc464 100644 --- a/build-aux/Doxyfile.in +++ b/build-aux/Doxyfile.in @@ -25,7 +25,7 @@ DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. -PROJECT_NAME = DMF +PROJECT_NAME = @PROJECT_NAME@ # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or @@ -564,8 +564,11 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ./lib/perc/src \ - ./lib/perc/include/dmf +INPUT = @CMAKE_SOURCE_DIR@/src \ + @CMAKE_SOURCE_DIR@/include/@PROJECT_NAME@ \ + @CMAKE_SOURCE_DIR@/include/@PROJECT_NAME@/marshal \ + @CMAKE_SOURCE_DIR@/include/@PROJECT_NAME@/connect \ + @CMAKE_SOURCE_DIR@/include/@PROJECT_NAME@/util # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -594,7 +597,7 @@ RECURSIVE = NO # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. -EXCLUDE = ./lib/perc/include/dmf/detail/mean_variance.hpp +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded diff --git a/config.h.in b/config.h.in index 70ae4ed..2425fef 100644 --- a/config.h.in +++ b/config.h.in @@ -1,3 +1,3 @@ /* erl_interface/src/epmd/ei_epmd.h is available */ #cmakedefine HAVE_EI_EPMD - +#cmakedefine ALIGNOF_UINT64_T diff --git a/include/eixx/alloc_pool.hpp b/include/eixx/alloc_pool.hpp index df59b75..cfb7a02 100644 --- a/include/eixx/alloc_pool.hpp +++ b/include/eixx/alloc_pool.hpp @@ -32,17 +32,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_ALLOC_POOL_HPP_ #define _EIXX_ALLOC_POOL_HPP_ -#include // definition of EIXX_NAMESPACE #include #define EIXX_USE_ALLOCATOR -namespace EIXX_NAMESPACE { +namespace eixx { typedef boost::fast_pool_allocator allocator_t; //typedef boost::pool_allocator allocator_t; -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_ALLOC_POOL_HPP_ diff --git a/include/eixx/alloc_pool_st.hpp b/include/eixx/alloc_pool_st.hpp index 6455eba..f492039 100644 --- a/include/eixx/alloc_pool_st.hpp +++ b/include/eixx/alloc_pool_st.hpp @@ -33,13 +33,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_ALLOC_POOL_HPP_ #define _EIXX_ALLOC_POOL_HPP_ -#include // definition of EIXX_NAMESPACE #include #include #define EIXX_USE_ALLOCATOR -namespace EIXX_NAMESPACE { +namespace eixx { typedef boost::fast_pool_allocator< char @@ -47,7 +46,7 @@ typedef boost::fast_pool_allocator< , boost::details::pool::null_mutex > allocator_t; -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_ALLOC_POOL_HPP_ diff --git a/include/eixx/alloc_std.hpp b/include/eixx/alloc_std.hpp index 2ffe613..b412022 100644 --- a/include/eixx/alloc_std.hpp +++ b/include/eixx/alloc_std.hpp @@ -33,15 +33,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define _EIXX_ALLOC_STD_HPP_ #include -#include // definition of EIXX_NAMESPACE #define EIXX_USE_ALLOCATOR -namespace EIXX_NAMESPACE { +namespace eixx { typedef std::allocator allocator_t; -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_ALLOC_STD_HPP_ diff --git a/include/eixx/alloc_std_debug.hpp b/include/eixx/alloc_std_debug.hpp index 4a5de35..4103274 100644 --- a/include/eixx/alloc_std_debug.hpp +++ b/include/eixx/alloc_std_debug.hpp @@ -33,13 +33,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_ALLOC_STD_HPP_ #define _EIXX_ALLOC_STD_HPP_ -#include // definition of EIXX_NAMESPACE #include #include #define EIXX_USE_ALLOCATOR -namespace EIXX_NAMESPACE { +namespace eixx { namespace detail { template @@ -95,7 +94,7 @@ struct allocator_t : public detail::debug_allocator }; }; -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_ALLOC_STD_HPP_ diff --git a/include/eixx/connect.hpp b/include/eixx/connect.hpp index 121a426..49f8f11 100644 --- a/include/eixx/connect.hpp +++ b/include/eixx/connect.hpp @@ -37,13 +37,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { typedef connect::transport_msg transport_msg; typedef connect::basic_otp_connection otp_connection; typedef connect::basic_otp_mailbox otp_mailbox; typedef connect::basic_otp_node otp_node; -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif diff --git a/include/eixx/connect/basic_otp_connection.hpp b/include/eixx/connect/basic_otp_connection.hpp index 6ce7053..fc9213f 100644 --- a/include/eixx/connect/basic_otp_connection.hpp +++ b/include/eixx/connect/basic_otp_connection.hpp @@ -39,7 +39,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { template class basic_otp_node; @@ -238,7 +238,7 @@ class basic_otp_connection }; } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_BASIC_OTP_CONNECTION_HPP_ diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index 6976296..f59e016 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -46,15 +46,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { template class basic_otp_node; -using EIXX_NAMESPACE::marshal::list; -using EIXX_NAMESPACE::marshal::epid; -using EIXX_NAMESPACE::marshal::tuple; -using EIXX_NAMESPACE::marshal::varbind; +using eixx::marshal::list; +using eixx::marshal::epid; +using eixx::marshal::tuple; +using eixx::marshal::varbind; using namespace std::chrono; /** @@ -356,13 +356,13 @@ class basic_otp_mailbox }; } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { template ostream& operator<< (ostream& out, - const EIXX_NAMESPACE::connect::basic_otp_mailbox& a_mbox) + const eixx::connect::basic_otp_mailbox& a_mbox) { return a_mbox.dump(out); } diff --git a/include/eixx/connect/basic_otp_mailbox.ipp b/include/eixx/connect/basic_otp_mailbox.ipp index 6d8d67c..e48aca0 100644 --- a/include/eixx/connect/basic_otp_mailbox.ipp +++ b/include/eixx/connect/basic_otp_mailbox.ipp @@ -33,7 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _EIXX_BASIC_OTP_MAILBOX_IPP_ #define _EIXX_BASIC_OTP_MAILBOX_IPP_ -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { //------------------------------------------------------------------------------ @@ -205,6 +205,6 @@ dump(std::ostream& out) const { } } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_BASIC_OTP_MAILBOX_IPP_ diff --git a/include/eixx/connect/basic_otp_mailbox_registry.hpp b/include/eixx/connect/basic_otp_mailbox_registry.hpp index 90abe2c..7a59e77 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.hpp +++ b/include/eixx/connect/basic_otp_mailbox_registry.hpp @@ -39,7 +39,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { using detail::lock_guard; @@ -116,7 +116,7 @@ struct basic_otp_mailbox_registry { }; } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #include diff --git a/include/eixx/connect/basic_otp_mailbox_registry.ipp b/include/eixx/connect/basic_otp_mailbox_registry.ipp index 40dee1b..3bfab14 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.ipp +++ b/include/eixx/connect/basic_otp_mailbox_registry.ipp @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define _EIXX_BASIC_OTP_MAILBOX_REGISTRTY_IPP_ #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { //----------------------------------------------------------------------------- @@ -227,6 +227,6 @@ void basic_otp_mailbox_registry::pids(std::list >& lis } } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_BASIC_OTP_MAILBOX_REGISTRTY_IPP_ diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index c6e6d87..a4f9f8e 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -48,10 +48,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { -using namespace EIXX_NAMESPACE; +using namespace eixx; using marshal::epid; using marshal::port; using marshal::ref; @@ -79,7 +79,7 @@ class basic_otp_node: public basic_otp_node_local { typedef transport_msg transport_msg_t; typedef basic_otp_connection connection_t; - typedef EIXX_NAMESPACE::detail::hash_map_base< + typedef eixx::detail::hash_map_base< atom, typename connection_t::pointer, atom_con_hash_fun > conn_hash_map; @@ -372,7 +372,7 @@ class basic_otp_node: public basic_otp_node_local { }; } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #include #include diff --git a/include/eixx/connect/basic_otp_node.ipp b/include/eixx/connect/basic_otp_node.ipp index 3ee1a7f..7bf3680 100644 --- a/include/eixx/connect/basic_otp_node.ipp +++ b/include/eixx/connect/basic_otp_node.ipp @@ -36,7 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { namespace { @@ -467,4 +467,4 @@ send_monitor_exit(const epid& a_from, const epid& a_to, } } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/include/eixx/connect/basic_otp_node_local.hpp b/include/eixx/connect/basic_otp_node_local.hpp index d072085..c26c31a 100644 --- a/include/eixx/connect/basic_otp_node_local.hpp +++ b/include/eixx/connect/basic_otp_node_local.hpp @@ -40,7 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { using marshal::atom; @@ -94,6 +94,6 @@ class basic_otp_node_local { }; } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_OTP_NODE_LOCAL_HPP_ diff --git a/include/eixx/connect/detail/basic_rpc_server.hpp b/include/eixx/connect/detail/basic_rpc_server.hpp index 2566b17..119a055 100644 --- a/include/eixx/connect/detail/basic_rpc_server.hpp +++ b/include/eixx/connect/detail/basic_rpc_server.hpp @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { using marshal::atom; @@ -175,6 +175,6 @@ const var basic_otp_node::rpc_server::T = var("T"); } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_BASIC_RPC_SERVER_HPP_ diff --git a/include/eixx/connect/test_helper.hpp b/include/eixx/connect/test_helper.hpp index aa81792..65e10a5 100644 --- a/include/eixx/connect/test_helper.hpp +++ b/include/eixx/connect/test_helper.hpp @@ -12,7 +12,7 @@ #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { class verboseness { @@ -44,7 +44,7 @@ class verboseness { typedef connect::verboseness verboseness; -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_TEST_HELPER_HPP_ diff --git a/include/eixx/connect/transport_msg.hpp b/include/eixx/connect/transport_msg.hpp index 8a9e942..c387e37 100644 --- a/include/eixx/connect/transport_msg.hpp +++ b/include/eixx/connect/transport_msg.hpp @@ -37,15 +37,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { -using EIXX_NAMESPACE::marshal::tuple; -using EIXX_NAMESPACE::marshal::list; -using EIXX_NAMESPACE::marshal::eterm; -using EIXX_NAMESPACE::marshal::epid; -using EIXX_NAMESPACE::marshal::ref; -using EIXX_NAMESPACE::marshal::trace; +using eixx::marshal::tuple; +using eixx::marshal::list; +using eixx::marshal::eterm; +using eixx::marshal::epid; +using eixx::marshal::ref; +using eixx::marshal::trace; /// Erlang distributed transport messages contain message type, /// control message with message routing and other details, and @@ -113,7 +113,7 @@ class transport_msg { const eterm& msg() const { return m_msg; } /// Returns true when the transport message contains message payload /// associated with SEND or REG_SEND message type. - bool has_msg() const { return m_msg.type() != EIXX_NAMESPACE::UNDEFINED; } + bool has_msg() const { return m_msg.type() != eixx::UNDEFINED; } /// Indicates that there was an error processing this message bool has_error() const { return (m_type & EXCEPTION) == EXCEPTION; } @@ -461,11 +461,11 @@ const char* transport_msg::type_string() const { } } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { template - ostream& operator<< (ostream& out, EIXX_NAMESPACE::connect::transport_msg& a_msg) { + ostream& operator<< (ostream& out, eixx::connect::transport_msg& a_msg) { return a_msg.dump(out); } } // namespace std diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index 64cbdcd..fbbbab4 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -44,7 +44,7 @@ #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { namespace posix = boost::asio::posix; @@ -344,7 +344,7 @@ class connection //------------------------------------------------------------------------------ } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #include diff --git a/include/eixx/connect/transport_otp_connection.ipp b/include/eixx/connect/transport_otp_connection.ipp index e9ce2fb..73dcfeb 100644 --- a/include/eixx/connect/transport_otp_connection.ipp +++ b/include/eixx/connect/transport_otp_connection.ipp @@ -39,10 +39,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include //#include // see erl_interface/src -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { -using EIXX_NAMESPACE::marshal::trace; +using eixx::marshal::trace; template const size_t connection::s_header_size = 4; @@ -485,7 +485,7 @@ send(const transport_msg& a_msg) } } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_TRANSPORT_OTP_CONNECTION_IPP_ diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 69dbead..a5fb79b 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -49,7 +49,7 @@ extern "C" { } #endif -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { #ifndef EIXX_HAVE_EI_EPMD @@ -201,7 +201,7 @@ class tcp_connection }; } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx //------------------------------------------------------------------------------ // connection_tcp implementation diff --git a/include/eixx/connect/transport_otp_connection_tcp.ipp b/include/eixx/connect/transport_otp_connection_tcp.ipp index 7f9b5f9..2e6ad1d 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.ipp +++ b/include/eixx/connect/transport_otp_connection_tcp.ipp @@ -36,7 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { //------------------------------------------------------------------------------ @@ -710,7 +710,7 @@ gen_digest(unsigned challenge, const char cookie[], uint8_t digest[16]) } } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_CONNECTION_TCP_IPP_ diff --git a/include/eixx/connect/transport_otp_connection_uds.hpp b/include/eixx/connect/transport_otp_connection_uds.hpp index 55400dc..ae843ab 100644 --- a/include/eixx/connect/transport_otp_connection_uds.hpp +++ b/include/eixx/connect/transport_otp_connection_uds.hpp @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { //---------------------------------------------------------------------------- @@ -107,6 +107,6 @@ class uds_connection //------------------------------------------------------------------------------ } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_TRANSPORT_OTP_CONNECTION_UDS_HPP_ diff --git a/include/eixx/connect/verbose.hpp b/include/eixx/connect/verbose.hpp index 489c426..a6dfa5b 100644 --- a/include/eixx/connect/verbose.hpp +++ b/include/eixx/connect/verbose.hpp @@ -11,7 +11,7 @@ #ifndef _EIXX_VERBOSE_HPP_ #define _EIXX_VERBOSE_HPP_ -namespace EIXX_NAMESPACE { +namespace eixx { // otp_node.on_status reporting level enum report_level { @@ -34,7 +34,7 @@ enum verbose_type { }; } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_VERBOSE_HPP_ diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index 7487a90..bc90aec 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -33,11 +33,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define _EIXX_ETERM_HPP_ #include -#include // definition of EIXX_NAMESPACE #include #include -namespace EIXX_NAMESPACE { +namespace eixx { typedef marshal::eterm eterm; typedef marshal::atom atom; @@ -68,6 +67,6 @@ namespace detail { BOOST_STATIC_ASSERT(sizeof(var) == sizeof(uint64_t)); } // namespace detail -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif diff --git a/include/eixx/eterm_exception.hpp b/include/eixx/eterm_exception.hpp index eaad2a0..a599ab2 100644 --- a/include/eixx/eterm_exception.hpp +++ b/include/eixx/eterm_exception.hpp @@ -37,7 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { /** * Base class for the other eixx erlang exception classes. @@ -199,6 +199,6 @@ class err_no_process: public err_bad_argument { err_no_process(const std::string &msg, T arg): err_bad_argument(msg, arg) {} }; -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_EXCEPTION_HPP_ diff --git a/include/eixx/marshal/alloc_base.hpp b/include/eixx/marshal/alloc_base.hpp index 1c5867d..2daa6bf 100644 --- a/include/eixx/marshal/alloc_base.hpp +++ b/include/eixx/marshal/alloc_base.hpp @@ -37,7 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -156,6 +156,6 @@ namespace marshal { }; } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_ETERM_BASE_HPP_ diff --git a/include/eixx/marshal/am.hpp b/include/eixx/marshal/am.hpp index 8ada959..1a85c3c 100644 --- a/include/eixx/marshal/am.hpp +++ b/include/eixx/marshal/am.hpp @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include -namespace EIXX_NAMESPACE { +namespace eixx { using marshal::atom; @@ -64,4 +64,4 @@ namespace EIXX_NAMESPACE { extern const atom am_unsupported; extern const atom am_user; -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 149a8ba..34b3d16 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -44,11 +44,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { namespace detail { - namespace eid = EIXX_NAMESPACE::detail; + namespace eid = eixx::detail; using eid::lock_guard; /// Create an atom containing node name. @@ -210,11 +210,11 @@ inline atom make_node_name(const std::string& s) } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { - inline ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::atom& s) { + inline ostream& operator<< (ostream& out, const eixx::marshal::atom& s) { return s.dump(out); } diff --git a/include/eixx/marshal/binary.hpp b/include/eixx/marshal/binary.hpp index 3dca95b..2c13707 100644 --- a/include/eixx/marshal/binary.hpp +++ b/include/eixx/marshal/binary.hpp @@ -41,7 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -145,16 +145,16 @@ class binary if (printable) return out << "<<" << string(data(), size()) << ">>"; else - return EIXX_NAMESPACE::to_binary_string(out, data(), size()); + return eixx::to_binary_string(out, data(), size()); } }; } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { template - ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::binary& a) { + ostream& operator<< (ostream& out, const eixx::marshal::binary& a) { return a.dump(out); } diff --git a/include/eixx/marshal/binary.ipp b/include/eixx/marshal/binary.ipp index bec96d5..6fce5ff 100644 --- a/include/eixx/marshal/binary.ipp +++ b/include/eixx/marshal/binary.ipp @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -70,4 +70,4 @@ void binary::encode(char* buf, int& idx, size_t size) const } } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/include/eixx/marshal/defaults.hpp b/include/eixx/marshal/defaults.hpp index be1acf1..812bce6 100644 --- a/include/eixx/marshal/defaults.hpp +++ b/include/eixx/marshal/defaults.hpp @@ -33,10 +33,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define _EIXX_DEFAULTS_HPP #include -#include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { // Forward declarations @@ -134,7 +133,7 @@ namespace EIXX_NAMESPACE { } } -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_DEFAULTS_HPP diff --git a/include/eixx/marshal/detail/array_variadic_init.hpp b/include/eixx/marshal/detail/array_variadic_init.hpp index efafbcb..e24a058 100644 --- a/include/eixx/marshal/detail/array_variadic_init.hpp +++ b/include/eixx/marshal/detail/array_variadic_init.hpp @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { namespace detail { @@ -63,6 +63,6 @@ namespace detail { } // namespace detail } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_ARRAY_VARIADIC_INIT_HPP_ diff --git a/include/eixx/marshal/endian.hpp b/include/eixx/marshal/endian.hpp index 567cd3a..4d370d7 100644 --- a/include/eixx/marshal/endian.hpp +++ b/include/eixx/marshal/endian.hpp @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { template inline void put_be(char*& s, T n) { @@ -71,6 +71,6 @@ inline uint16_t get16be(const char*& s) { uint16_t n; get_be(s, n); return n; } inline uint32_t get32be(const char*& s) { uint32_t n; get_be(s, n); return n; } inline uint64_t get64be(const char*& s) { uint64_t n; get_be(s, n); return n; } -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_ENDIAN_HPP_ diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 2c381e2..e79f957 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -55,7 +55,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { namespace { @@ -608,11 +608,11 @@ template T& get(eterm& t) { } } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { template - ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::eterm& a_term) { + ostream& operator<< (ostream& out, const eixx::marshal::eterm& a_term) { return out << a_term.to_string(); } } diff --git a/include/eixx/marshal/eterm.ipp b/include/eixx/marshal/eterm.ipp index 8577dab..cb2652f 100644 --- a/include/eixx/marshal/eterm.ipp +++ b/include/eixx/marshal/eterm.ipp @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { inline eterm_type type_string_to_type(const char* s, size_t n) { eterm_type r = UNDEFINED; @@ -417,4 +417,4 @@ void eterm::format(atom& m, atom& f, eterm& args, const char* fmt, } } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/include/eixx/marshal/eterm_format.hpp b/include/eixx/marshal/eterm_format.hpp index a9d8eec..a25c7e1 100644 --- a/include/eixx/marshal/eterm_format.hpp +++ b/include/eixx/marshal/eterm_format.hpp @@ -33,7 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { /** @@ -65,7 +65,7 @@ static void eformat(atom& mod, atom& fun, eterm& args, const char** fmt, va_list* pa, const Alloc& a_alloc = Alloc()); } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx #include diff --git a/include/eixx/marshal/eterm_format.ipp b/include/eixx/marshal/eterm_format.ipp index 1224d33..14eeb17 100644 --- a/include/eixx/marshal/eterm_format.ipp +++ b/include/eixx/marshal/eterm_format.ipp @@ -54,7 +54,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include //#include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { namespace { @@ -463,5 +463,5 @@ namespace marshal { } } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index 8980c62..c8f12cb 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -42,7 +42,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { // Forward declaration @@ -298,6 +298,6 @@ class eterm_pattern_action { }; } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EI_MATCH_HPP_ diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index f2e1a80..553bc56 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -39,7 +39,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -342,12 +342,12 @@ class list::iterator { }; } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { template - ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::list& a) { + ostream& operator<< (ostream& out, const eixx::marshal::list& a) { return a.dump(out); } diff --git a/include/eixx/marshal/list.ipp b/include/eixx/marshal/list.ipp index c759882..6aa1979 100644 --- a/include/eixx/marshal/list.ipp +++ b/include/eixx/marshal/list.ipp @@ -37,7 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -274,4 +274,4 @@ std::ostream& list::dump(std::ostream& out, const varbind* vars) c } } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index af7a6f2..549f897 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -39,7 +39,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { /** @@ -233,11 +233,11 @@ class epid { }; } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { template - ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::epid& a) { + ostream& operator<< (ostream& out, const eixx::marshal::epid& a) { return a.dump(out); } diff --git a/include/eixx/marshal/pid.ipp b/include/eixx/marshal/pid.ipp index 6090931..8093a4d 100644 --- a/include/eixx/marshal/pid.ipp +++ b/include/eixx/marshal/pid.ipp @@ -33,7 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -85,4 +85,4 @@ void epid::encode(char* buf, int& idx, size_t size) const } } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index f386a60..4495e18 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { /** @@ -180,11 +180,11 @@ class port { }; } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { template - ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::port& a) { + ostream& operator<< (ostream& out, const eixx::marshal::port& a) { return out << "#Port<" << a.node() << "." << a.id() << ">"; } diff --git a/include/eixx/marshal/port.ipp b/include/eixx/marshal/port.ipp index 9893c9e..b01b2ed 100644 --- a/include/eixx/marshal/port.ipp +++ b/include/eixx/marshal/port.ipp @@ -33,7 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -79,4 +79,4 @@ void port::encode(char* buf, int& idx, size_t size) const } } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index de1df5b..dfffde7 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -40,7 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { namespace detail { } // namespace detail @@ -227,7 +227,7 @@ class ref { }; } //namespace marshal -} //namespace EIXX_NAMESPACE +} //namespace eixx namespace std { /** @@ -235,7 +235,7 @@ namespace std { * as \verbatim #Ref \endverbatim **/ template - ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::ref& a) { + ostream& operator<< (ostream& out, const eixx::marshal::ref& a) { return out << "#Ref<" << a.node() << '.' << a.id(0) << '.' << a.id(1) << '.' << a.id(2) << '>'; } diff --git a/include/eixx/marshal/ref.ipp b/include/eixx/marshal/ref.ipp index 607602f..2992b89 100644 --- a/include/eixx/marshal/ref.ipp +++ b/include/eixx/marshal/ref.ipp @@ -35,7 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -107,4 +107,4 @@ void ref::encode(char* buf, int& idx, size_t size) const } } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index b00f0ee..5c64bf1 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -41,7 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template class varbind; @@ -253,27 +253,27 @@ string::string(const char* buf, int& idx, size_t size, const Alloc& a_all } } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { template - ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::string& s) { + ostream& operator<< (ostream& out, const eixx::marshal::string& s) { return out << '"' << s.c_str() << '"'; } template - bool operator== (const std::string& lhs, const EIXX_NAMESPACE::marshal::string& rhs) { + bool operator== (const std::string& lhs, const eixx::marshal::string& rhs) { return lhs == rhs.c_str(); } template - bool operator== (const EIXX_NAMESPACE::marshal::string& lhs, const std::string& rhs) { + bool operator== (const eixx::marshal::string& lhs, const std::string& rhs) { return rhs == rhs.c_str(); } template - bool operator== (const EIXX_NAMESPACE::marshal::string& lhs, const char* rhs) { + bool operator== (const eixx::marshal::string& lhs, const char* rhs) { return strcmp(rhs, lhs.c_str(), lhs.size()) == 0; } diff --git a/include/eixx/marshal/trace.hpp b/include/eixx/marshal/trace.hpp index fa76120..6c9c499 100644 --- a/include/eixx/marshal/trace.hpp +++ b/include/eixx/marshal/trace.hpp @@ -41,7 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { /// Represents trace operations performed on the trace::tracer. @@ -164,11 +164,11 @@ class trace : protected tuple { }; } //namespace marshal -} //namespace EIXX_NAMESPACE +} //namespace eixx namespace std { template - ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::trace& a) { + ostream& operator<< (ostream& out, const eixx::marshal::trace& a) { return a.dump(out); } diff --git a/include/eixx/marshal/tuple.hpp b/include/eixx/marshal/tuple.hpp index 13f12df..d93ec99 100644 --- a/include/eixx/marshal/tuple.hpp +++ b/include/eixx/marshal/tuple.hpp @@ -42,7 +42,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template class eterm; @@ -334,12 +334,12 @@ class tuple { }; } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { template - ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::tuple& a) { + ostream& operator<< (ostream& out, const eixx::marshal::tuple& a) { return a.dump(out); } diff --git a/include/eixx/marshal/tuple.ipp b/include/eixx/marshal/tuple.ipp index afdb818..9227320 100644 --- a/include/eixx/marshal/tuple.ipp +++ b/include/eixx/marshal/tuple.ipp @@ -37,7 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -128,4 +128,4 @@ std::ostream& tuple::dump(std::ostream& out, const varbind* vars) } } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/include/eixx/marshal/var.hpp b/include/eixx/marshal/var.hpp index 97ea7e1..1f12a4c 100644 --- a/include/eixx/marshal/var.hpp +++ b/include/eixx/marshal/var.hpp @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { /** @@ -141,12 +141,12 @@ class var BOOST_STATIC_ASSERT(sizeof(var) == 8); } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { template - ostream& operator<< (ostream& out, EIXX_NAMESPACE::marshal::var s) { - return s.dump(out, (const EIXX_NAMESPACE::marshal::varbind*)NULL); + ostream& operator<< (ostream& out, eixx::marshal::var s) { + return s.dump(out, (const eixx::marshal::varbind*)NULL); } } // namespace std diff --git a/include/eixx/marshal/varbind.hpp b/include/eixx/marshal/varbind.hpp index d06e86f..d783135 100644 --- a/include/eixx/marshal/varbind.hpp +++ b/include/eixx/marshal/varbind.hpp @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { /// Name-value pair associating an eterm with an atom name @@ -177,13 +177,13 @@ class varbind { }; } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { template - ostream& operator<< (ostream& out, const EIXX_NAMESPACE::marshal::varbind& binding) { - using namespace EIXX_NAMESPACE::marshal; + ostream& operator<< (ostream& out, const eixx::marshal::varbind& binding) { + using namespace eixx::marshal; for (typename varbind::eterm_map_t::const_iterator it = binding.m_term_map.begin(); it != binding.m_term_map.end(); ++it) diff --git a/include/eixx/marshal/visit.hpp b/include/eixx/marshal/visit.hpp index 1618049..e370b2a 100644 --- a/include/eixx/marshal/visit.hpp +++ b/include/eixx/marshal/visit.hpp @@ -35,7 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template class tuple; @@ -78,6 +78,6 @@ struct static_visitor { }; } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _IMPL_VISIT_HPP_ diff --git a/include/eixx/marshal/visit_encode_size.hpp b/include/eixx/marshal/visit_encode_size.hpp index 0ec8461..39ae677 100644 --- a/include/eixx/marshal/visit_encode_size.hpp +++ b/include/eixx/marshal/visit_encode_size.hpp @@ -35,7 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -50,7 +50,7 @@ struct visit_eterm_encode_size_calc size_t operator()(const T& a) const { return a.encode_size(); } }; -} // namespace EIXX_NAMESPACE -} // namespace EIXX_NAMESPACE +} // namespace eixx +} // namespace eixx #endif // _IMPL_VISIT_ENCODE_SIZE_HPP_ diff --git a/include/eixx/marshal/visit_encoder.hpp b/include/eixx/marshal/visit_encoder.hpp index e0eba3f..9adf09b 100644 --- a/include/eixx/marshal/visit_encoder.hpp +++ b/include/eixx/marshal/visit_encoder.hpp @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { class visit_eterm_encoder: public static_visitor { @@ -55,6 +55,6 @@ class visit_eterm_encoder: public static_visitor { }; } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _IMPL_VISIT_ENCODER_HPP_ diff --git a/include/eixx/marshal/visit_match.hpp b/include/eixx/marshal/visit_match.hpp index a218ee6..5e40752 100644 --- a/include/eixx/marshal/visit_match.hpp +++ b/include/eixx/marshal/visit_match.hpp @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -66,7 +66,7 @@ class visit_eterm_match } }; -} // namespace EIXX_NAMESPACE -} // namespace EIXX_NAMESPACE +} // namespace eixx +} // namespace eixx #endif // _IMPL_VISIT_MATCH_HPP_ diff --git a/include/eixx/marshal/visit_subst.hpp b/include/eixx/marshal/visit_subst.hpp index 79fbe5c..2d69e26 100644 --- a/include/eixx/marshal/visit_subst.hpp +++ b/include/eixx/marshal/visit_subst.hpp @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -59,7 +59,7 @@ class visit_eterm_subst bool operator()(const T& a) const { return false; } }; -} // namespace EIXX_NAMESPACE -} // namespace EIXX_NAMESPACE +} // namespace eixx +} // namespace eixx #endif // _IMPL_VISIT_SUBST_HPP_ diff --git a/include/eixx/marshal/visit_to_string.hpp b/include/eixx/marshal/visit_to_string.hpp index fa4bee3..539eec9 100644 --- a/include/eixx/marshal/visit_to_string.hpp +++ b/include/eixx/marshal/visit_to_string.hpp @@ -37,7 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace marshal { template @@ -65,6 +65,6 @@ class visit_eterm_stringify }; } // namespace marshal -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _IMPL_VISIT_TO_STRING_HPP_ diff --git a/include/eixx/namespace.hpp b/include/eixx/namespace.hpp deleted file mode 100644 index 84d98df..0000000 --- a/include/eixx/namespace.hpp +++ /dev/null @@ -1,39 +0,0 @@ -//---------------------------------------------------------------------------- -/// \file namespace.hpp -//---------------------------------------------------------------------------- -/// \brief Header file for defining eixx namespace name -//---------------------------------------------------------------------------- -// Copyright (c) 2010 Serge Aleynikov -// Created: 2010-09-20 -//---------------------------------------------------------------------------- -/* -***** BEGIN LICENSE BLOCK ***** - -This file is part of the eixx (Erlang C++ Interface) Library. - -Copyright (C) 2010 Serge Aleynikov - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -***** END LICENSE BLOCK ***** -*/ -#ifndef _EIXX_NAMESPACE_HPP_ -#define _EIXX_NAMESPACE_HPP_ - -#ifndef EIXX_NAMESPACE -#define EIXX_NAMESPACE eixx -#endif - -#endif diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index 9cdaaee..7ab00d4 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -40,10 +40,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -#include // definition of EIXX_NAMESPACE #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace util { using namespace boost::system::errc; @@ -223,4 +222,4 @@ struct async_queue : std::enable_shared_from_this> }; } // namespace util -} // namespace EIXX_NAMESPACE \ No newline at end of file +} // namespace eixx diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 073eb9a..6bb0bec 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -43,10 +43,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace util { - namespace eid = EIXX_NAMESPACE::detail; + namespace eid = eixx::detail; using eid::lock_guard; /// Non-garbage collected hash table for atoms. It stores strings @@ -148,6 +148,6 @@ namespace util { typedef basic_atom_table<> atom_table; } // namespace util -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif diff --git a/include/eixx/util/common.hpp b/include/eixx/util/common.hpp index 814fdbf..073ec6a 100644 --- a/include/eixx/util/common.hpp +++ b/include/eixx/util/common.hpp @@ -1,7 +1,7 @@ //---------------------------------------------------------------------------- /// \file common.hpp //---------------------------------------------------------------------------- -/// \namespace dmf Distributed Monitoring Framework. +/// \namespace eixx EI C++ Interface Library /// /// This file contains a set of commonly used functions. //---------------------------------------------------------------------------- @@ -29,7 +29,7 @@ #define ERL_DEMONITOR_P 20 #define ERL_MONITOR_P_EXIT 21 -namespace EIXX_NAMESPACE { +namespace eixx { #if BOOST_VERSION > 104800 namespace bid = boost::interprocess::ipcdetail; @@ -50,7 +50,7 @@ namespace bid = boost::interprocess::detail; /// \def ON_ERROR_CALLBACK(Client, S) /// Invokes an error callback from within perc_client's implementation. /// -/// @param Client is of type 'dmf::client' +/// @param Connection is of type 'eixx::connection' /// @param S is the stream of elements to include in the message. /// The elements can be concatinated with left shift /// notation. @@ -113,7 +113,7 @@ int find_index(const char* (&a_list)[N], const char* a_string, int a_default=-1) return a_default; } -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_COMMON_HPP_ diff --git a/include/eixx/util/compiler_hints.hpp b/include/eixx/util/compiler_hints.hpp index 07f694a..59a6abe 100644 --- a/include/eixx/util/compiler_hints.hpp +++ b/include/eixx/util/compiler_hints.hpp @@ -15,7 +15,7 @@ #include // Branch prediction optimization (see http://lwn.net/Articles/255364/) -namespace EIXX_NAMESPACE { +namespace eixx { #ifndef NO_HINT_BRANCH_PREDICTION inline bool likely(bool expr) { return boost::lockfree::detail::likely (expr); } @@ -26,7 +26,7 @@ namespace EIXX_NAMESPACE { #endif -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_COMPILER_HINTS_HPP_ diff --git a/include/eixx/util/hashtable.hpp b/include/eixx/util/hashtable.hpp index b7f1461..0895662 100644 --- a/include/eixx/util/hashtable.hpp +++ b/include/eixx/util/hashtable.hpp @@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #endif -namespace EIXX_NAMESPACE { +namespace eixx { namespace detail { namespace src = @@ -110,7 +110,7 @@ struct hsieh_hash_fun { typedef detail::hash_map_base char_int_hash_map; -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_HASHTABLE_HPP_ diff --git a/include/eixx/util/string_util.hpp b/include/eixx/util/string_util.hpp index 965ef10..2c1a346 100644 --- a/include/eixx/util/string_util.hpp +++ b/include/eixx/util/string_util.hpp @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { /// Print the content of a buffer to \a out stream in the form: /// \verbatim <> \endverbatim where Ik is @@ -62,7 +62,7 @@ static inline std::string to_binary_string(const char* a, size_t sz) { return oss.str(); } -} // namespace EIXX_NAMESPACE +} // namespace eixx namespace std { diff --git a/include/eixx/util/sync.hpp b/include/eixx/util/sync.hpp index 8629880..3be5c0a 100644 --- a/include/eixx/util/sync.hpp +++ b/include/eixx/util/sync.hpp @@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #endif -namespace EIXX_NAMESPACE { +namespace eixx { namespace detail { #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L @@ -53,7 +53,7 @@ template struct lock_guard: public boost::lock_guard { #endif } // namespace detail -} // namespace EIXX_NAMESPACE +} // namespace eixx #endif // _EIXX_SYNC_HPP_ diff --git a/src/am.cpp b/src/am.cpp index 68b3a2f..a9d8043 100644 --- a/src/am.cpp +++ b/src/am.cpp @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { const atom am_badarg = atom("badarg"); const atom am_badrpc = atom("badrpc"); @@ -50,5 +50,5 @@ namespace EIXX_NAMESPACE { const atom am_unsupported = atom("unsupported"); const atom am_user = atom("user"); -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/src/basic_otp_node_local.cpp b/src/basic_otp_node_local.cpp index 0ac86ad..ae74ea1 100644 --- a/src/basic_otp_node_local.cpp +++ b/src/basic_otp_node_local.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace EIXX_NAMESPACE { +namespace eixx { namespace connect { namespace { @@ -121,4 +121,4 @@ void basic_otp_node_local::set_nodename( } } // namespace connect -} // namespace EIXX_NAMESPACE +} // namespace eixx diff --git a/src/server.hpp b/src/server.hpp index 19c3fed..6c49760 100644 --- a/src/server.hpp +++ b/src/server.hpp @@ -8,15 +8,14 @@ // Created: 2010-04-11 // -#ifndef _SERVER_HPP_ -#define _SERVER_HPP_ +#pragma once #include #include #include #include "channel.hpp" -namespace perc { +namespace eixx { //------------------------------------------------------------------------------ // channel_manager class @@ -337,6 +336,4 @@ class uds_server : public server< Handler > } }; -} // namespace perc - -#endif // _SERVER_HPP_ +} // namespace eixx diff --git a/src/test_node.cpp b/src/test_node.cpp index c896c6f..cf57ac6 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -7,7 +7,7 @@ #include -using namespace EIXX_NAMESPACE; +using namespace eixx; void usage(char* exe) { printf("Usage: %s -n NODE -r REMOTE_NODE [-c COOKIE] [-v VERBOSE] [-t RECONNECT_SECS]\n" diff --git a/test/test_eterm_format.cpp b/test/test_eterm_format.cpp index f284784..25db668 100644 --- a/test/test_eterm_format.cpp +++ b/test/test_eterm_format.cpp @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -using namespace EIXX_NAMESPACE; +using namespace eixx; BOOST_AUTO_TEST_CASE( test_eterm_format_string ) { diff --git a/test/test_eterm_match.cpp b/test/test_eterm_match.cpp index 287cbe6..e6c25a0 100644 --- a/test/test_eterm_match.cpp +++ b/test/test_eterm_match.cpp @@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "test_alloc.hpp" #include -using namespace EIXX_NAMESPACE; +using namespace eixx; BOOST_AUTO_TEST_CASE( test_match1 ) { diff --git a/test/test_eterm_pool.cpp b/test/test_eterm_pool.cpp index 995e80b..1a8ac21 100644 --- a/test/test_eterm_pool.cpp +++ b/test/test_eterm_pool.cpp @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "test_alloc.hpp" #include -using namespace EIXX_NAMESPACE; +using namespace eixx; BOOST_AUTO_TEST_CASE( test_encode_atom_t ) { diff --git a/test/test_eterm_refc.cpp b/test/test_eterm_refc.cpp index 427c966..b57dd7c 100644 --- a/test/test_eterm_refc.cpp +++ b/test/test_eterm_refc.cpp @@ -25,8 +25,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "test_alloc.hpp" #include -using namespace EIXX_NAMESPACE; -using EIXX_NAMESPACE::marshal::eterm; +using namespace eixx; +using eixx::marshal::eterm; template struct counted_alloc : public std::allocator { diff --git a/test/test_perf.cpp b/test/test_perf.cpp index 2ed5148..eea9ced 100644 --- a/test/test_perf.cpp +++ b/test/test_perf.cpp @@ -4,7 +4,7 @@ #include #include -using namespace EIXX_NAMESPACE; +using namespace eixx; int iterations=200000; From eff066f70a5a42c2408369e7ea329e24daf5e022 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 01:28:33 -0500 Subject: [PATCH 071/185] Fix build issues - stable cmake build --- CMakeLists.txt | 5 ++- build-aux/CMakeAlignOf.cmake | 45 +++++++++++++++++++ config.h.in | 2 +- .../connect/transport_otp_connection_tcp.hpp | 4 +- include/eixx/eterm.hpp | 2 +- 5 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 build-aux/CMakeAlignOf.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 10a5ae6..dd0114e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,11 +177,12 @@ set(EIXX_LIBS #include(${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake) #include(${CMAKE_ROOT}/Modules/CheckStructHasMember.cmake) include(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +include(${CMAKE_SOURCE_DIR}/build-aux/CMakeAlignOf.cmake) set(CMAKE_REQUIRED_INCLUDES ${Erl_ERL_INTERFACE_DIR}/src) CHECK_INCLUDE_FILE(epmd/ei_epmd.h HAVE_EI_EPMD) -# Needed for pcap.hpp tests -#CHECK_STRUCT_HAS_MEMBER("struct tcphdr" th_flags netinet/tcp.h UTXX_HAVE_TCPHDR_TH_FLAGS_H) +unset(CMAKE_REQUIRED_INCLUDES) +ALIGNOF(uint64_t cpp UINT64_T) #------------------------------------------------------------------------------- # Configure files diff --git a/build-aux/CMakeAlignOf.cmake b/build-aux/CMakeAlignOf.cmake new file mode 100644 index 0000000..4f0e60f --- /dev/null +++ b/build-aux/CMakeAlignOf.cmake @@ -0,0 +1,45 @@ +MACRO(ALIGNOF TYPE LANG NAME) + + IF(NOT ALIGNOF_${NAME}) + + # + # Try to compile and run a foo grogram. + # The alignment result will be stored in ALIGNOF_${CHECK_TYPE} + # + + SET(INCLUDE_HEADERS + "#include + #include + #include ") + + FOREACH(File ${CMAKE_REQUIRED_INCLUDES}) + SET(INCLUDE_HEADERS "${INCLUDE_HEADERS}\n#include <${File}>\n") + ENDFOREACH() + #IF(HAVE_STDINT_H) + SET(INCLUDE_HEADERS "${INCLUDE_HEADERS}\n#include \n") + #ENDIF() + + FILE (WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/c_get_${NAME}_alignment.${LANG}" + "${INCLUDE_HEADERS} + int main(){ + char diff; + struct foo {char a; ${TYPE} b;}; + struct foo *p = (struct foo *) malloc(sizeof(struct foo)); + diff = ((char *)&p->b) - ((char *)&p->a); + return diff; + }" + ) + + TRY_RUN(ALIGNOF_${NAME} COMPILE_RESULT "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/" + "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/c_get_${NAME}_alignment.${LANG}" + COMPILE_OUTPUT_VARIABLE "ALIGNOF_${NAME}_COMPILE_VAR") + + IF (NOT COMPILE_RESULT) + MESSAGE(FATAL_ERROR "Check alignment of ${TYPE} in ${LANG}: compilation failed: ${ALIGNOF_${NAME}_COMPILE_VAR}") + ELSE() + MESSAGE(STATUS "Check alignment of ${TYPE} in ${LANG}: ${ALIGNOF_${NAME}}") + ENDIF() + + ENDIF() + +ENDMACRO() diff --git a/config.h.in b/config.h.in index 2425fef..51233b0 100644 --- a/config.h.in +++ b/config.h.in @@ -1,3 +1,3 @@ /* erl_interface/src/epmd/ei_epmd.h is available */ #cmakedefine HAVE_EI_EPMD -#cmakedefine ALIGNOF_UINT64_T +#cmakedefine ALIGNOF_UINT64_T @ALIGNOF_UINT64_T@ diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index a5fb79b..80517ef 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -39,7 +39,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include -#ifdef EIXX_HAVE_EI_EPMD +#ifdef HAVE_EI_EPMD extern "C" { #include // see erl_interface/src @@ -52,7 +52,7 @@ extern "C" { namespace eixx { namespace connect { -#ifndef EIXX_HAVE_EI_EPMD +#ifndef HAVE_EI_EPMD // These constants are not exposed by EI headers: static const char ERL_VERSION_MAGIC = 131; static const short EPMD_PORT = 4369; diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index bc90aec..35008ee 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -54,7 +54,7 @@ typedef marshal::eterm_pattern_matcher eterm_pattern_matcher; typedef marshal::eterm_pattern_action eterm_pattern_action; namespace detail { - BOOST_STATIC_ASSERT(sizeof(eterm) == (EIXX_ALIGNOF_UINT64_T > sizeof(int) ? EIXX_ALIGNOF_UINT64_T : sizeof(int)) + sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(eterm) == (ALIGNOF_UINT64_T > sizeof(int) ? ALIGNOF_UINT64_T : sizeof(int)) + sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(atom) <= sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(string) <= sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(binary) <= sizeof(uint64_t)); From 4185d9f9401fa5348280f40ff90ef8e355c49b18 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 01:31:04 -0500 Subject: [PATCH 072/185] Update README --- README.md | 55 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index be4624e..6ecaf65 100644 --- a/README.md +++ b/README.md @@ -42,20 +42,55 @@ Repository location: http://github.com/saleyn/eixx ### Building ### -Make sure that you have [autoconf-archive] -(http://www.gnu.org/software/autoconf-archive) package installed. +This library is dependent on BOOST. -Run: +If you need to customize location of BOOST or installation prefix, create a file called +`.cmake-args.${HOSTNAME}`. Alternatively if you are doing multi-host build with +identical configuration, create a file call `.cmake-args`. E.g.: - $ ./bootstrap - $ ./configure --with-boost="/path/to/boost" [--with-erlang="/path/to/erlang"] \ - [--prefix="/target/install/path"] - $ make - $ make install # Default install path is ./install +There are three sets of variables present in this file: + +1. Build and install locations. + + * `DIR:BUILD=...` - Build directory + * `DIR:INSTALL=...` - Install directory + + They may contain macros: + + * `@PROJECT@` - name of current project (from CMakeList.txt) + * `@VERSION@` - project version number (from CMakeList.txt) + * `@BUILD@` - build type (from command line) + * `${...}` - environment variable + +2. `ENV:VAR=...` - Environment var set before running cmake + +3. `VAR=...` - Variable passed to cmake with -D prefix -For clang add before ./configure: - $ CC="clang -DBOOST_ASIO_HAS_STD_CHRONO" CXX="clang++ -DBOOST_ASIO_HAS_STD_CHRONO" ./configure <...> +Example: +``` +$ cat > .cmake-args.${HOSTNAME} +DIR:BUILD=/tmp/@PROJECT@/build +DIR:INSTALL=/opt/pkt/@PROJECT@/@VERSION@ +ENV:BOOST_ROOT=/opt/pkg/boost/current +ENV:BOOST_LIBRARYDIR=/opt/pkg/boost/current/gcc/lib +PKG_ROOT_DIR=/opt/pkg +``` +Run: +``` +$ make bootstrap [toolchain=gcc|clang] [build=Debug|Release] \ + [generator=make|ninja] [prefix=/usr/local] [verbose=true] +$ make [verbose=true] +$ make install # Default install path is /usr/local +``` +After running `make bootstrap` two local links are created `build` and `inst` +pointing to build and installation directories. +If you need to do a full cleanup of the current build and rerun bootstrap with +previously chosen options, do: +``` +$ make distclean +$ make rebootstrap +``` ### Author ### From b854ecaab8ed3efa8f7004b60a5735afbb7b91bb Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 08:24:46 -0500 Subject: [PATCH 073/185] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ecaf65..0ab0f34 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ Serge Aleynikov ### LICENSE ### -GNU Lesser General Public License +Apache Public License v2.0 ### Example ### From de281914cdfbd98274348ef3432ebe9415956765 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 08:45:04 -0500 Subject: [PATCH 074/185] Bug fix in list::nth() --- .travis.yml | 51 ++++++++++++++++++++++ include/eixx/connect/basic_otp_mailbox.ipp | 1 - include/eixx/marshal/list.hpp | 8 ++-- test/test_eterm.cpp | 2 +- 4 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2a1680f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,51 @@ +language: cpp +compiler: g++ +addons: + apt: + sources: + - ubuntu-toolchain-r-test + - boost-latest + packages: + - gcc-4.9 + - g++-4.9 + - libboost1.55-all-dev + - libxslt1.1 + - python-lxml + - doxygen + +before_install: + - lsb_release -a + - uname -a + - sudo apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ trusty main restricted" + - sudo add-apt-repository -y "deb http://ppa.launchpad.net/dns/gnu/ubuntu precise main" + - sudo add-apt-repository -y "deb http://ppa.launchpad.net/wnoronha/thrift/ubuntu precise main" + - sudo add-apt-repository -y "deb http://ppa.launchpad.net/kzemek/boost/ubuntu utopic main" + - sudo add-apt-repository ppa:george-edison55/precise-backports --yes + - sudo apt-get update -qq + - sudo apt-get install cmake-data cmake + - # sudo apt-get install libboost1.55-all-dev + - # sudo updatedb + - # dpkg -S /usr/include/boost/version.hpp + - # sudo dpkg -L libboost1.55-all-dev + - # find /usr/include/boost -print | head -100 + - # grep BOOST_LIB_VERSION /usr/include/boost/version.hpp | grep define + - # locate libboost | head -100 + - sudo apt-get install -qq libthrift-dev libthrift0 thrift-compiler + - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 90 + +before_script: + - echo "DIR:BUILD=/tmp/${USER}/utxx" > .cmake-args.$(hostname) + - echo "DIR:INSTALL=/tmp/${USER}/install/@PROJECT@/@VERSION@" >> .cmake-args.$(hostname) + - echo "PKG_ROOT_DIR=/usr/local" >> .cmake-args.$(hostname) + - echo "WITH_THRIFT=OFF" >> .cmake-args.$(hostname) + - echo "BOOST_INCLUDEDIR=/usr/include" >> .cmake-args.$(hostname) + - echo "BOOST_LIBRARYDIR=/usr/lib/x86_64-linux-gnu" >> .cmake-args.$(hostname) + - echo "WITH_ENUM_SERIALIZATION=ON" >> .cmake-args.$(hostname) + - g++ --version +script: + - make bootstrap generator=make build=Debug + - make + - make doc + - make test +branches: + only: master diff --git a/include/eixx/connect/basic_otp_mailbox.ipp b/include/eixx/connect/basic_otp_mailbox.ipp index e48aca0..6d15819 100644 --- a/include/eixx/connect/basic_otp_mailbox.ipp +++ b/include/eixx/connect/basic_otp_mailbox.ipp @@ -92,7 +92,6 @@ async_match(const marshal::eterm_pattern_matcher& a_matcher, (transport_msg*& a_msg, const boost::system::error_code& ec) { if (this->m_time_freed.time_since_epoch().count() == 0) return false; - bool res; if (ec) { a_on_timeout(*this); return false; diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 553bc56..776978d 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -177,18 +177,18 @@ class list : protected alloc_base, Alloc> { void close() { header()->initialized = true; } /// Return list length. This method has O(1) complexity. - size_t length() const { return m_blob ? header()->size : 0; } + size_t length() const { return m_blob ? header()->size : 0; } bool empty() const { return !m_blob || header()->size == 0; } - bool initialized() const { return m_blob && header()->initialized; } + bool initialized() const { return m_blob && header()->initialized; } /// Return pointer to the N'th element in the list. This method has /// O(N) complexity. const eterm& nth(size_t n) const throw(err_bad_argument) { if (n > length()) throw err_bad_argument("Index out of bounds", n); - const_iterator it = begin(), endit = end(); size_t i = 0; - for(; it != endit, i < n; ++it, ++i); + auto it = begin(); + for(auto endit = end(); it != endit && i < n; ++it, ++i); return *it; } diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index a079c51..3c007a9 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -191,7 +191,7 @@ BOOST_AUTO_TEST_CASE( test_list3 ) { list t = list::make(1, alloc); BOOST_REQUIRE_EQUAL(1ul, t.length()); - BOOST_REQUIRE_EQUAL(1, t.nth(0).to_long()); + BOOST_REQUIRE_EQUAL(1l, t.nth(0).to_long()); } { const list& t = list::make(1, 2, alloc); From 8d9c592a86125700b933da25a38db0dcd18be1e3 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 08:59:56 -0500 Subject: [PATCH 075/185] Add dot to travis for doxygen build --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2a1680f..887a870 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,8 +21,10 @@ before_install: - sudo add-apt-repository -y "deb http://ppa.launchpad.net/wnoronha/thrift/ubuntu precise main" - sudo add-apt-repository -y "deb http://ppa.launchpad.net/kzemek/boost/ubuntu utopic main" - sudo add-apt-repository ppa:george-edison55/precise-backports --yes + - sudo apt-add-repository ppa:dperry/ppa-graphviz-test - sudo apt-get update -qq - sudo apt-get install cmake-data cmake + - sudo apt-get install graphviz - # sudo apt-get install libboost1.55-all-dev - # sudo updatedb - # dpkg -S /usr/include/boost/version.hpp From 8c9f35737d79256be48d67d5b4b50973be72bda3 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 09:06:41 -0500 Subject: [PATCH 076/185] Add graphviz to Travis --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 887a870..5e7ea22 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ addons: - libboost1.55-all-dev - libxslt1.1 - python-lxml + - graphviz - doxygen before_install: @@ -21,10 +22,8 @@ before_install: - sudo add-apt-repository -y "deb http://ppa.launchpad.net/wnoronha/thrift/ubuntu precise main" - sudo add-apt-repository -y "deb http://ppa.launchpad.net/kzemek/boost/ubuntu utopic main" - sudo add-apt-repository ppa:george-edison55/precise-backports --yes - - sudo apt-add-repository ppa:dperry/ppa-graphviz-test - sudo apt-get update -qq - sudo apt-get install cmake-data cmake - - sudo apt-get install graphviz - # sudo apt-get install libboost1.55-all-dev - # sudo updatedb - # dpkg -S /usr/include/boost/version.hpp From 121807529fab8c85b3791e7e21a4c01b72331f5d Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 09:35:31 -0500 Subject: [PATCH 077/185] Fix release warnings --- .travis.yml | 1 + CMakeLists.txt | 1 - include/eixx/connect/transport_otp_connection_tcp.hpp | 4 ++++ include/eixx/connect/transport_otp_connection_tcp.ipp | 6 +++--- test/test_async_queue.cpp | 2 -- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5e7ea22..6ad8a1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,6 +47,7 @@ script: - make bootstrap generator=make build=Debug - make - make doc + - make install - make test branches: only: master diff --git a/CMakeLists.txt b/CMakeLists.txt index dd0114e..e156b06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,6 @@ project(eixx VERSION 1.4) # CMAKE options customization #=============================================================================== option(VERBOSE "Turn verbosity on|off" OFF) -#set(DEBUG "vars") if(VERBOSE) set(CMAKE_VERBOSE_MAKEFILE ON) diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 80517ef..b2d839b 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -157,13 +157,17 @@ class tcp_connection std::string remote_alivename() const { auto s = this->remote_nodename().to_string(); +#ifndef NDEBUG auto n = s.find('@'); +#endif BOOST_ASSERT(n != std::string::npos); return s.substr(0, s.find('@')); } std::string remote_hostname() const { auto s = this->remote_nodename().to_string(); +#ifndef NDEBUG auto n = s.find('@'); +#endif BOOST_ASSERT(n != std::string::npos); return s.substr(s.find('@')+1); } diff --git a/include/eixx/connect/transport_otp_connection_tcp.ipp b/include/eixx/connect/transport_otp_connection_tcp.ipp index 2e6ad1d..3c5b07e 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.ipp +++ b/include/eixx/connect/transport_otp_connection_tcp.ipp @@ -237,7 +237,7 @@ void tcp_connection::handle_epmd_read_body( } m_epmd_wr += bytes_transferred; - #ifndef BOOST_DISABLE_ASSERTS + #ifndef NDEBUG int got_bytes = m_epmd_wr - m_buf_epmd; #endif BOOST_ASSERT(got_bytes >= 10); @@ -484,7 +484,7 @@ void tcp_connection::handle_read_challenge_body( } m_node_wr += bytes_transferred; - #ifndef BOOST_DISABLE_ASSERTS + #ifndef NDEBUG int got_bytes = m_node_wr - m_node_rd; #endif BOOST_ASSERT(got_bytes >= (int)m_expect_size); @@ -607,7 +607,7 @@ void tcp_connection::handle_read_challenge_ack_body( } m_node_wr += bytes_transferred; - #ifndef BOOST_DISABLE_ASSERTS + #ifndef NDEBUG int got_bytes = m_node_wr - m_node_rd; #endif BOOST_ASSERT(got_bytes >= (int)m_expect_size); diff --git a/test/test_async_queue.cpp b/test/test_async_queue.cpp index 9600a16..cebe13e 100644 --- a/test/test_async_queue.cpp +++ b/test/test_async_queue.cpp @@ -103,8 +103,6 @@ namespace { const int producer_thread_count = 4; std::atomic_int done_producer_count(0); - int total_iterations = producer_thread_count * iterations; - std::atomic done (false); } From 34c9bf464b68304c99f8c52008c930e925a60f17 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 11:47:25 -0500 Subject: [PATCH 078/185] Fix build --- CMakeLists.txt | 82 +++++++----------- .../{CMakeAlignOf.cmake => AlignOf.cmake} | 0 build-aux/FindErlang.cmake | 86 +++++++++++++++++++ eixx.pc.in | 16 ++-- include/eixx/util/async_queue.hpp | 14 +-- test/CMakeLists.txt | 14 +-- 6 files changed, 143 insertions(+), 69 deletions(-) rename build-aux/{CMakeAlignOf.cmake => AlignOf.cmake} (100%) create mode 100644 build-aux/FindErlang.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index e156b06..f928287 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,18 +85,27 @@ set(CMAKE_INSTALL_RPATH "${CMAKE_BINARY_DIR}/src:${CMAKE_INSTALL_PREFIX}/lib") # which point to directories outside the build tree to the install RPATH set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +#------------------------------------------------------------------------------- +# Custom cmake libs +#------------------------------------------------------------------------------- +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/build-aux) + +#include(${CMAKE_ROOT}/Modules/CheckTypeSize.cmake) +#include(${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake) +#include(${CMAKE_ROOT}/Modules/CheckStructHasMember.cmake) +include(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +include(${CMAKE_SOURCE_DIR}/build-aux/AlignOf.cmake) +#include(${CMAKE_SOURCE_DIR}/build-aux/FindErlang.cmake) + #------------------------------------------------------------------------------- # Dependent packages and their directory locations #------------------------------------------------------------------------------- find_package(PkgConfig) -find_program(ERL erl) find_package(OpenSSL REQUIRED) +find_package(Erlang REQUIRED) set(PKG_ROOT_DIR "/opt/pkg" CACHE STRING "Package root directory") -# Python -find_package(PythonInterp) - # Boost (with local modifications): set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_MULTITHREAD ON) @@ -115,44 +124,33 @@ if(Boost_FOUND) endif() set(Boost_LIBRARIES - ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_REGEX_LIBRARY} - ${Boost_DATE_TIME_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_SYSTEM_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${Boost_IOSTREAMS_LIBRARY} -) - -execute_process( - COMMAND ${ERL} -eval "io:format(\"~s\", [code:root_dir()]), halt()." - -noshell -noinput - OUTPUT_VARIABLE Erl_DIR -) -execute_process( - COMMAND ${ERL} -eval "io:format(\"~s\", [code:lib_dir(erl_interface)]), halt()." - -noshell -noinput - OUTPUT_VARIABLE Erl_ERL_INTERFACE_DIR + boost_system + boost_thread +# ${Boost_REGEX_LIBRARY} +# ${Boost_DATE_TIME_LIBRARY} +# ${Boost_FILESYSTEM_LIBRARY} +# ${Boost_PROGRAM_OPTIONS_LIBRARY} +# ${Boost_IOSTREAMS_LIBRARY} ) -message(STATUS "Erl interface: ${Erl_ERL_INTERFACE_DIR}") -set(AddCleanFiles) # Additional clean files +#------------------------------------------------------------------------------- +# Platform-specific checks +#------------------------------------------------------------------------------- +set(CMAKE_REQUIRED_INCLUDES ${ERLANG_EI_PATH}/src) +CHECK_INCLUDE_FILE(epmd/ei_epmd.h HAVE_EI_EPMD) +unset(CMAKE_REQUIRED_INCLUDES) +ALIGNOF(uint64_t cpp UINT64_T) #------------------------------------------------------------------------------- # MAKE options #------------------------------------------------------------------------------- -#add_custom_target(vars -# COMMAND ${CMAKE_COMMAND} -H${CMAKE_SOURCE_DIR} -B${CMAKE_BINARY_DIR} -LA -#) - include_directories( SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} - ${Erl_DIR}/usr/include - ${Erl_ERL_INTERFACE_DIR}/src + ${Erlang_EI_INCLUDE_DIR} + ${Erlang_EI_DIR}/src ) include_directories( ${CMAKE_SOURCE_DIR}/include @@ -160,29 +158,15 @@ include_directories( ) link_directories( ${Boost_LIBRARY_DIRS} - ${Erl_DIR}/usr/lib + ${Erlang_EI_LIBRARY_DIR} ) set(EIXX_LIBS - ei + ${Erlang_EI_LIBRARIES} ${OPENSSL_LIBRARIES} # For MD5 support pthread ) -#------------------------------------------------------------------------------- -# Platform-specific checks -#------------------------------------------------------------------------------- -#include(${CMAKE_ROOT}/Modules/CheckTypeSize.cmake) -#include(${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake) -#include(${CMAKE_ROOT}/Modules/CheckStructHasMember.cmake) -include(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) -include(${CMAKE_SOURCE_DIR}/build-aux/CMakeAlignOf.cmake) - -set(CMAKE_REQUIRED_INCLUDES ${Erl_ERL_INTERFACE_DIR}/src) -CHECK_INCLUDE_FILE(epmd/ei_epmd.h HAVE_EI_EPMD) -unset(CMAKE_REQUIRED_INCLUDES) -ALIGNOF(uint64_t cpp UINT64_T) - #------------------------------------------------------------------------------- # Configure files #------------------------------------------------------------------------------- @@ -195,8 +179,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.in" # Srcs and Targets: #------------------------------------------------------------------------------- -add_subdirectory(src) -add_subdirectory(test) +add_subdirectory(${CMAKE_SOURCE_DIR}/src) +add_subdirectory(${CMAKE_SOURCE_DIR}/test) #=============================================================================== # Installation diff --git a/build-aux/CMakeAlignOf.cmake b/build-aux/AlignOf.cmake similarity index 100% rename from build-aux/CMakeAlignOf.cmake rename to build-aux/AlignOf.cmake diff --git a/build-aux/FindErlang.cmake b/build-aux/FindErlang.cmake new file mode 100644 index 0000000..a6cf5b7 --- /dev/null +++ b/build-aux/FindErlang.cmake @@ -0,0 +1,86 @@ +# vim:ts=2:sw=2:et +# - Find Erlang +# This module finds if Erlang is installed and determines where the +# include files and libraries are. This code sets the following +# variables: +# +# Erlang_ERL = the full path to the Erlang runtime +# Erlang_COMPILE = the full path to the Erlang compiler +# Erlang_EI_DIR = the full path to the Erlang erl_interface path +# Erlang_ERTS_DIR = the full path to the Erlang erts path +# Erlang_EI_INCLUDE_DIR = /include appended to Erlang_EI_DIR +# Erlang_EI_LIBRARY_DIR = /lib appended to Erlang_EI_DIR +# Erlang_ERTS_INCLUDE_DIR = /include appended to Erlang_ERTS_DIR +# Erlang_ERTS_LIBRARY_DIR = /lib appended to Erlang_ERTS_DIR +# + +SET(ERLANG_BIN_PATH + $ENV{ERLANG_HOME}/bin + /opt/bin + /sw/bin + /usr/bin + /usr/local/bin + /opt/local/bin + ) +FIND_PROGRAM(Erlang_ERL + NAMES erl + PATHS ${ERLANG_BIN_PATH} +) + +FIND_PROGRAM(Erlang_COMPILE + NAMES erlc + PATHS ${ERLANG_BIN_PATH} +) + +EXECUTE_PROCESS( + COMMAND erl -noshell -eval "io:format(\"~s\", [code:lib_dir()])" -s erlang halt + OUTPUT_VARIABLE Erlang_OTP_LIB_DIR +) + +EXECUTE_PROCESS( + COMMAND erl -noshell -eval "io:format(\"~s\", [code:root_dir()])" -s erlang halt + OUTPUT_VARIABLE Erlang_OTP_ROOT_DIR +) + +EXECUTE_PROCESS( + COMMAND + erl -noshell -eval "io:format(\"~s\", [code:lib_dir(erl_interface)])" -s erlang halt + OUTPUT_VARIABLE Erlang_EI_DIR +) + +MESSAGE(STATUS "Using OTP lib: ${Erlang_OTP_LIB_DIR} - found") + +EXECUTE_PROCESS( + COMMAND ls ${Erlang_OTP_ROOT_DIR} + COMMAND grep erts + COMMAND sort -n + COMMAND tail -1 + COMMAND tr -d \n + OUTPUT_VARIABLE Erlang_ERTS_DIR +) + +MESSAGE(STATUS "Using erl_interface version: ${Erlang_EI_DIR}") +MESSAGE(STATUS "Using erts version: ${Erlang_ERTS_DIR}") + +SET(Erlang_EI_DIR ${Erlang_EI_DIR} CACHE STRING "Erlang EI Dir") +SET(Erlang_EI_INCLUDE_DIR ${Erlang_OTP_ROOT_DIR}/usr/include CACHE STRING "Erlang EI Include Dir") +SET(Erlang_EI_LIBRARY_DIR ${Erlang_OTP_ROOT_DIR}/usr/lib CACHE STRING "Erlang EI Libary Dir") +SET(Erlang_EI_LIBRARIES ei CACHE STRING "Erlang EI Libraries") + +SET(Erlang_DIR ${Erlang_OTP_ROOT_DIR} CACHE STRING "Erlang Root Dir") +SET(Erlang_ERTS_DIR ${Erlang_OTP_ROOT_DIR}/${Erlang_ERTS_DIR}) +SET(Erlang_ERTS_INCLUDE_DIR ${Erlang_OTP_ROOT_DIR}/${Erlang_ERTS_DIR}/include) +SET(Erlang_ERTS_LIBRARY_DIR ${Erlang_OTP_ROOT_DIR}/${Erlang_ERTS_DIR}/lib) + +FIND_PROGRAM(Erlang_ARCHIVE + NAMES zip + PATHS ${ERLANG_BIN_PATH} +) +MARK_AS_ADVANCED( + Erlang_ERL + Erlang_COMPILE + Erlang_ARCHIVE +# Erlang_EI_DIR +# Erlang_EI_INCLUDE_DIR +# Erlang_EI_LIBRARY_DIR +) diff --git a/eixx.pc.in b/eixx.pc.in index 055f372..83eb385 100644 --- a/eixx.pc.in +++ b/eixx.pc.in @@ -1,12 +1,12 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@CMAKE_INSTALL_PREFIX@/lib +includedir=@CMAKE_INSTALL_PREFIX@/include -Name: @PACKAGE@ +Name: @PROJECT_NAME@ Description: EIXX: C++ Interface to Erlang #Requires: boost_1_55_0 -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} @EI_LDFLAGS@ -Wl,-rpath,${libdir} -leixx @EI_LIB@ @CRYPTO_LIBS@ -Cflags: -I${includedir} @EI_CPPFLAGS@ +Version: @PROJECT_VERSION@ +Libs: -L${libdir} -L@Erlang_EI_LIBRARY_PATH@ -Wl,-rpath,${libdir} -leixx -lei -lssl -lcrypto +Cflags: -I${includedir} -I@Erlang_EI_INCLUDE_DIR@ diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index 7ab00d4..a7e279b 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -72,10 +72,9 @@ struct async_queue : std::enable_shared_from_this> // Dequeue up to m_batch_size of items and for each one call // m_wait_handler - void process_queue(const async_handler& h, const boost::system::error_code& ec, + template + void process_queue(const Handler& h, const boost::system::error_code& ec, std::chrono::milliseconds repeat, int repeat_count) { - if (h == nullptr) return; - // Process up to m_batch_size items waiting on the queue. // For each dequeued item call m_wait_handler @@ -120,7 +119,8 @@ struct async_queue : std::enable_shared_from_this> } // Called by io_service on timeout of m_timer - void operator() (async_handler h, const boost::system::error_code& ec, + template + void operator() (const Handler& h, const boost::system::error_code& ec, std::chrono::milliseconds repeat, int repeat_count) { process_queue(h, ec, repeat, repeat_count); } @@ -172,14 +172,16 @@ struct async_queue : std::enable_shared_from_this> /// Call \a a_on_data handler asyncronously on next message in the queue. /// /// @returns true if the call was handled synchronously - bool async_dequeue(const async_handler& a_on_data, int repeat_count = 0) { + template + bool async_dequeue(const Handler& a_on_data, int repeat_count = 0) { return async_dequeue(a_on_data, std::chrono::milliseconds(-1), repeat_count); } /// Call \a a_on_data handler asyncronously on next message in the queue. /// /// @returns true if the call was handled synchronously - bool async_dequeue(const async_handler& a_on_data, + template + bool async_dequeue(const Handler& a_on_data, std::chrono::milliseconds a_wait_duration = std::chrono::milliseconds(-1), int repeat_count = 0) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c5ee9cb..336fa9e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,26 +17,28 @@ target_compile_definitions(test-eterm PRIVATE -DBOOST_TEST_DYN_LINK) target_include_directories(test-eterm PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries( test-eterm - eixx ei + eixx + ${Erlang_EI_LIBRARIES} boost_unit_test_framework + ${Boost_LIBRARIES} boost_system - boost_thread ) add_executable(test-connect test_async_queue.cpp) target_link_libraries( test-connect eixx + ${Erlang_EI_LIBRARIES} boost_unit_test_framework - boost_system - boost_thread + ${Boost_LIBRARIES} ) add_executable(test-perf test_perf.cpp) target_link_libraries( test-perf - eixx ei - boost_system + eixx + ${Erlang_EI_LIBRARIES} + ${Boost_LIBRARIES} ) install( From ff5dd6905f6b24c271edd856b003f62b10ca11aa Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 13:56:47 -0500 Subject: [PATCH 079/185] Rename implementation files --- include/eixx/connect/basic_otp_connection.hpp | 12 +- include/eixx/connect/basic_otp_mailbox.hpp | 10 +- ..._otp_mailbox.ipp => basic_otp_mailbox.hxx} | 2 +- .../connect/basic_otp_mailbox_registry.hpp | 2 +- ...try.ipp => basic_otp_mailbox_registry.hxx} | 2 +- include/eixx/connect/basic_otp_node.hpp | 4 +- ...{basic_otp_node.ipp => basic_otp_node.hxx} | 2 +- .../eixx/connect/detail/basic_rpc_server.hpp | 15 ++- .../eixx/connect/transport_otp_connection.hpp | 21 +-- ...ction.ipp => transport_otp_connection.hxx} | 2 +- .../connect/transport_otp_connection_tcp.hpp | 11 +- ...p.ipp => transport_otp_connection_tcp.hxx} | 126 +++++++++++------- include/eixx/marshal/binary.hpp | 2 +- .../eixx/marshal/{binary.ipp => binary.hxx} | 2 +- include/eixx/marshal/eterm.hpp | 2 +- include/eixx/marshal/{eterm.ipp => eterm.hxx} | 2 +- include/eixx/marshal/eterm_format.hpp | 2 +- .../{eterm_format.ipp => eterm_format.hxx} | 0 include/eixx/marshal/list.hpp | 2 +- include/eixx/marshal/{list.ipp => list.hxx} | 2 +- include/eixx/marshal/pid.hpp | 2 +- include/eixx/marshal/{pid.ipp => pid.hxx} | 2 +- include/eixx/marshal/port.hpp | 2 +- include/eixx/marshal/{port.ipp => port.hxx} | 2 +- include/eixx/marshal/ref.hpp | 2 +- include/eixx/marshal/{ref.ipp => ref.hxx} | 2 +- include/eixx/marshal/tuple.hpp | 2 +- include/eixx/marshal/{tuple.ipp => tuple.hxx} | 2 +- include/eixx/util/async_queue.hpp | 17 ++- src/server.hpp | 6 +- src/test_node.cpp | 28 ++-- test/test_async_queue.cpp | 2 +- 32 files changed, 166 insertions(+), 126 deletions(-) rename include/eixx/connect/{basic_otp_mailbox.ipp => basic_otp_mailbox.hxx} (99%) rename include/eixx/connect/{basic_otp_mailbox_registry.ipp => basic_otp_mailbox_registry.hxx} (99%) rename include/eixx/connect/{basic_otp_node.ipp => basic_otp_node.hxx} (99%) rename include/eixx/connect/{transport_otp_connection.ipp => transport_otp_connection.hxx} (99%) rename include/eixx/connect/{transport_otp_connection_tcp.ipp => transport_otp_connection_tcp.hxx} (89%) rename include/eixx/marshal/{binary.ipp => binary.hxx} (99%) rename include/eixx/marshal/{eterm.ipp => eterm.hxx} (99%) rename include/eixx/marshal/{eterm_format.ipp => eterm_format.hxx} (100%) rename include/eixx/marshal/{list.ipp => list.hxx} (99%) rename include/eixx/marshal/{pid.ipp => pid.hxx} (99%) rename include/eixx/marshal/{port.ipp => port.hxx} (99%) rename include/eixx/marshal/{ref.ipp => ref.hxx} (99%) rename include/eixx/marshal/{tuple.ipp => tuple.hxx} (99%) diff --git a/include/eixx/connect/basic_otp_connection.hpp b/include/eixx/connect/basic_otp_connection.hpp index fc9213f..89fc2d2 100644 --- a/include/eixx/connect/basic_otp_connection.hpp +++ b/include/eixx/connect/basic_otp_connection.hpp @@ -38,6 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include namespace eixx { namespace connect { @@ -46,7 +47,7 @@ template class basic_otp_node; template class basic_otp_connection - : public std::enable_shared_from_this > { + : public boost::enable_shared_from_this > { public: typedef basic_otp_connection self; typedef connection, Alloc> connection_type; @@ -96,9 +97,10 @@ class basic_otp_connection if (m_abort || m_reconnect_secs <= 0) return; m_reconnect_timer.expires_from_now(boost::posix_time::seconds(m_reconnect_secs)); - m_reconnect_timer.async_wait( - std::bind(&self::timer_reconnect, this->shared_from_this(), - std::placeholders::_1)); + auto pthis = this->shared_from_this(); + m_reconnect_timer.async_wait([pthis](auto& ec) { + pthis->timer_reconnect(ec); + }); } void timer_reconnect(const boost::system::error_code& ec) { @@ -117,7 +119,7 @@ class basic_otp_connection } public: - typedef std::shared_ptr > pointer; + using pointer = boost::shared_ptr>; boost::asio::io_service& io_service() { return m_io_service; } connection_type* transport() { return m_transport.get(); } diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index f59e016..4fdca4d 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -93,7 +93,7 @@ template class basic_otp_mailbox { public: - typedef std::shared_ptr > pointer; + using pointer = boost::shared_ptr>; typedef std::function< bool (basic_otp_mailbox&, transport_msg*&) @@ -114,7 +114,7 @@ class basic_otp_mailbox atom m_name; std::set > m_links; std::map, epid > m_monitors; - std::shared_ptr m_queue; + boost::shared_ptr m_queue; system_clock::time_point m_time_freed; // Cache time of this mbox void do_deliver(transport_msg* a_msg); @@ -139,9 +139,7 @@ class basic_otp_mailbox , m_queue(new queue_type(m_io_service, a_queue_size, a_alloc)) {} - ~basic_otp_mailbox() { - close(); - } + ~basic_otp_mailbox() { close(); } /// @param a_reg_remove when true the mailbox's pid is removed from registry. /// Only pass false when invoking from the registry on destruction. @@ -369,6 +367,6 @@ namespace std { } // namespace std -#include +#include #endif // _EIXX_BASIC_OTP_MAILBOX_HPP_ diff --git a/include/eixx/connect/basic_otp_mailbox.ipp b/include/eixx/connect/basic_otp_mailbox.hxx similarity index 99% rename from include/eixx/connect/basic_otp_mailbox.ipp rename to include/eixx/connect/basic_otp_mailbox.hxx index 6d15819..1c5fcd4 100644 --- a/include/eixx/connect/basic_otp_mailbox.ipp +++ b/include/eixx/connect/basic_otp_mailbox.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file basic_otp_mailbox.ipp +/// \file basic_otp_mailbox.hxx //---------------------------------------------------------------------------- /// \brief Implemention of basic mailbox functionality. //---------------------------------------------------------------------------- diff --git a/include/eixx/connect/basic_otp_mailbox_registry.hpp b/include/eixx/connect/basic_otp_mailbox_registry.hpp index 7a59e77..2ed5399 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.hpp +++ b/include/eixx/connect/basic_otp_mailbox_registry.hpp @@ -118,6 +118,6 @@ struct basic_otp_mailbox_registry { } // namespace connect } // namespace eixx -#include +#include #endif // _EIXX_BASIC_OTP_MAILBOX_REGISTRTY_HPP_ diff --git a/include/eixx/connect/basic_otp_mailbox_registry.ipp b/include/eixx/connect/basic_otp_mailbox_registry.hxx similarity index 99% rename from include/eixx/connect/basic_otp_mailbox_registry.ipp rename to include/eixx/connect/basic_otp_mailbox_registry.hxx index 3bfab14..5d8375a 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.ipp +++ b/include/eixx/connect/basic_otp_mailbox_registry.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file basic_otp_mailbox_registry.ipp +/// \file basic_otp_mailbox_registry.hxx //---------------------------------------------------------------------------- /// \brief Implemention details of mailbox registration functionality //---------------------------------------------------------------------------- diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index a4f9f8e..993b97d 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -85,6 +85,7 @@ class basic_otp_node: public basic_otp_node_local { class rpc_server; + Mutex m_lock; uint8_t m_creation; std::atomic_int m_pid_count; std::atomic_int m_port_count; @@ -92,7 +93,6 @@ class basic_otp_node: public basic_otp_node_local { std::atomic_int m_refid1; boost::asio::io_service& m_io_service; - Mutex m_lock; basic_otp_mailbox_registry m_mailboxes; conn_hash_map m_connections; Alloc m_allocator; @@ -374,7 +374,7 @@ class basic_otp_node: public basic_otp_node_local { } // namespace connect } // namespace eixx -#include +#include #include #endif // _EIXX_BASIC_OTP_NODE_HPP_ diff --git a/include/eixx/connect/basic_otp_node.ipp b/include/eixx/connect/basic_otp_node.hxx similarity index 99% rename from include/eixx/connect/basic_otp_node.ipp rename to include/eixx/connect/basic_otp_node.hxx index 7bf3680..7673095 100644 --- a/include/eixx/connect/basic_otp_node.ipp +++ b/include/eixx/connect/basic_otp_node.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file basic_otp_mailbox.ipp +/// \file basic_otp_mailbox.hxx //---------------------------------------------------------------------------- /// \brief Implementation of mailbox interface functions. //---------------------------------------------------------------------------- diff --git a/include/eixx/connect/detail/basic_rpc_server.hpp b/include/eixx/connect/detail/basic_rpc_server.hpp index 119a055..618773c 100644 --- a/include/eixx/connect/detail/basic_rpc_server.hpp +++ b/include/eixx/connect/detail/basic_rpc_server.hpp @@ -131,24 +131,27 @@ class basic_otp_node::rpc_server : private Alloc { marshal::eterm_pattern_action( this->get_allocator(), - std::bind(&basic_otp_node::rpc_call, &m_node, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), + [this](auto& pat, auto& binding, auto opaque) { + this->m_node.rpc_call(pat, binding, opaque); + }, 0, "{'$gen_call', {~w, ~w}, {call, ~w, ~w, ~w, ~w}}", P, R, M, F, A, G), marshal::eterm_pattern_action( this->get_allocator(), - std::bind(&basic_otp_node::rpc_call, &m_node, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), + [this](auto& pat, auto& binding, auto opaque) { + this->m_node.rpc_call(pat, binding, opaque); + }, 1, "{'$gen_cast', {cast, ~w, ~w, ~w, ~w}}", M, F, A, G), marshal::eterm_pattern_action( this->get_allocator(), - std::bind(&basic_otp_node::rpc_call, &m_node, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), + [this](auto& pat, auto& binding, auto opaque) { + this->m_node.rpc_call(pat, binding, opaque); + }, 2, "{_, {~w, ~w}, _Cmd}}", P, R) diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index fbbbab4..dcb06e6 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -65,7 +65,7 @@ const char* connection_type_to_str(connection_type a_type); template class connection : private boost::noncopyable - , public std::enable_shared_from_this< connection > + , public boost::enable_shared_from_this< connection > { protected: static const size_t s_header_size; @@ -160,9 +160,9 @@ class connection boost::asio::buffer_size(*it)); m_handler->report_status(REPORT_INFO, s.str()); } + auto pthis = this->shared_from_this(); async_write(buffers, boost::asio::transfer_all(), - std::bind(&connection::handle_write, this->shared_from_this(), - std::placeholders::_1)); + [pthis](auto& ec, std::size_t) { pthis->handle_write(ec); }); } } @@ -209,8 +209,8 @@ class connection } boost::asio::const_buffer b(data, sz); - m_io_service.post( - std::bind(&connection::do_write, this->shared_from_this(), b)); + auto pthis = this->shared_from_this(); + m_io_service.post([pthis, b]() { pthis->do_write(b); }); } /// Get connection type from string. If successful the string is @@ -250,11 +250,12 @@ class connection m_handler->on_connect(this); const boost::asio::mutable_buffers_1 buffers(m_rd_end, rd_capacity()); + auto pthis = this->shared_from_this(); async_read( buffers, boost::asio::transfer_at_least(s_header_size), - std::bind(&connection::handle_read, this->shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); + [pthis](auto& ec, auto bytes) { pthis->handle_read(ec, bytes); } + ); } template @@ -264,8 +265,8 @@ class connection void async_write(const MutableBuffers& b, const CompletionCondition& c, ReadHandler h); public: - typedef Handler handler_type; - typedef std::shared_ptr > pointer; + using handler_type = Handler; + using pointer = boost::shared_ptr>; /// Create a connection object given of specific type and connect to peer /// endpoint given by \a a_addr. @@ -346,6 +347,6 @@ class connection } // namespace connect } // namespace eixx -#include +#include #endif // _EIXX_TRANSPORT_OTP_CONNECTION_HPP_ diff --git a/include/eixx/connect/transport_otp_connection.ipp b/include/eixx/connect/transport_otp_connection.hxx similarity index 99% rename from include/eixx/connect/transport_otp_connection.ipp rename to include/eixx/connect/transport_otp_connection.hxx index 73dcfeb..1607c31 100644 --- a/include/eixx/connect/transport_otp_connection.ipp +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file transport_otp_connection.ipp +/// \file transport_otp_connection.hxx //---------------------------------------------------------------------------- // Copyright (c) 2010 Serge Aleynikov // Created: 2010-09-11 diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index b2d839b..98d83c5 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -93,7 +93,8 @@ class tcp_connection void stop(const boost::system::error_code& e) { if (this->handler()->verbose() >= VERBOSE_TRACE) std::cout << "Calling connection_tcp::stop(" << e.message() << ')' << std::endl; - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); m_state = CS_INIT; base_t::stop(e); } @@ -143,9 +144,9 @@ class tcp_connection void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie) throw(std::runtime_error); - std::shared_ptr > shared_from_this() { - std::shared_ptr > p = base_t::shared_from_this(); - return *reinterpret_cast >*>(&p); + boost::shared_ptr > shared_from_this() { + boost::shared_ptr > p = base_t::shared_from_this(); + return *reinterpret_cast >*>(&p); } /// Set the socket to non-blocking mode and issue on_connect() callback. @@ -210,7 +211,7 @@ class tcp_connection //------------------------------------------------------------------------------ // connection_tcp implementation //------------------------------------------------------------------------------ -#include +#include #endif // _EIXX_TRANSPORT_OTP_CONNECTION_TCP_HPP_ diff --git a/include/eixx/connect/transport_otp_connection_tcp.ipp b/include/eixx/connect/transport_otp_connection_tcp.hxx similarity index 89% rename from include/eixx/connect/transport_otp_connection_tcp.ipp rename to include/eixx/connect/transport_otp_connection_tcp.hxx index 3c5b07e..c1c0afe 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.ipp +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file connection_tcp.ipp +/// \file connection_tcp.hxx //---------------------------------------------------------------------------- /// \brief Implementation of TCP connectivity transport with an Erlang node. //---------------------------------------------------------------------------- @@ -68,22 +68,23 @@ void tcp_connection::connect( //boost::system::error_code err = boost::asio::error::host_not_found; std::stringstream es; - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); // First resolve remote host name and connect to EPMD to find out the // node's port number. const char* epmd_port_s = getenv("ERL_EPMD_PORT"); - std::stringstream str; - str << EPMD_PORT; - const char* epmd_port = (epmd_port_s != NULL) ? epmd_port_s : str.str().c_str(); + auto epmd_port = (epmd_port_s != NULL) ? epmd_port_s : std::to_string(EPMD_PORT); + auto host = remote_hostname(); - tcp::resolver::query q(remote_hostname(), epmd_port); - m_state = CS_WAIT_RESOLVE; - m_resolver.async_resolve(q, - std::bind(&tcp_connection::handle_resolve, shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); + tcp::resolver::query q(host, epmd_port); + m_state = CS_WAIT_RESOLVE; + auto pthis = this->shared_from_this(); + m_resolver.async_resolve(q, [pthis](auto& err, auto& ep_iterator) { + pthis->handle_resolve(err, ep_iterator); + }); } template @@ -100,10 +101,12 @@ void tcp_connection::handle_resolve( // Attempt a connection to the first endpoint in the list. Each endpoint // will be tried until we successfully establish a connection. m_peer_endpoint = *ep_iterator; - m_state = CS_WAIT_EPMD_CONNECT; - m_socket.async_connect(m_peer_endpoint, - std::bind(&tcp_connection::handle_epmd_connect, shared_from_this(), - std::placeholders::_1, ++ep_iterator)); + m_state = CS_WAIT_EPMD_CONNECT; + auto pthis = this->shared_from_this(); + auto epnext = ++ep_iterator; + m_socket.async_connect(m_peer_endpoint, [pthis, epnext](auto& err) { + pthis->handle_epmd_connect(err, epnext); + }); } template @@ -127,22 +130,32 @@ void tcp_connection::handle_epmd_connect( this->handler()->report_status(REPORT_INFO, s.str()); } - m_state = CS_WAIT_EPMD_WRITE_DONE; + m_state = CS_WAIT_EPMD_WRITE_DONE; + auto pthis = this->shared_from_this(); + /* + boost::asio::async_write(m_socket, boost::asio::buffer(m_buf_epmd, len+2), + [pthis](auto& err) { pthis->handle_epmd_write(err); }); + */ boost::asio::async_write(m_socket, boost::asio::buffer(m_buf_epmd, len+2), - std::bind(&tcp_connection::handle_epmd_write, shared_from_this(), - std::placeholders::_1)); + std::bind(&tcp_connection::handle_epmd_write, pthis, + std::placeholders::_1)); } else if (ep_iterator != boost::asio::ip::tcp::resolver::iterator()) { // The connection failed. Try the next endpoint in the list. - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); m_peer_endpoint = *ep_iterator; + auto pthis = this->shared_from_this(); + auto epnext = ++ep_iterator; m_socket.async_connect(m_peer_endpoint, - std::bind(&tcp_connection::handle_epmd_connect, shared_from_this(), - std::placeholders::_1, ++ep_iterator)); + [pthis, epnext](auto& err) { + pthis->handle_epmd_connect(err, epnext); + }); } else { std::stringstream str; str << "Error connecting to epmd at host '" << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); } } @@ -154,10 +167,11 @@ void tcp_connection::handle_epmd_write(const boost::system::erro std::stringstream str; str << "Error writing to epmd at host '" << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } - + m_state = CS_WAIT_EPMD_REPLY; m_epmd_wr = m_buf_epmd; boost::asio::async_read(m_socket, boost::asio::buffer(m_buf_epmd, sizeof(m_buf_epmd)), @@ -176,7 +190,8 @@ void tcp_connection::handle_epmd_read_header( std::stringstream str; str << "Error reading response from epmd at host '" << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -187,7 +202,8 @@ void tcp_connection::handle_epmd_read_header( std::stringstream str; str << "Error unknown response from epmd at host '" << this->remote_nodename() << "': " << res; this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -204,7 +220,8 @@ void tcp_connection::handle_epmd_read_header( std::stringstream str; str << "Node " << this->remote_nodename() << " not known to epmd!"; this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -232,7 +249,8 @@ void tcp_connection::handle_epmd_read_body( std::stringstream str; str << "Error reading response body from epmd at host '" << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -260,7 +278,8 @@ void tcp_connection::handle_epmd_read_body( m_peer_endpoint.port(port); m_peer_endpoint.address( m_socket.remote_endpoint().address() ); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); if (m_dist_version <= 4) { std::stringstream str; str << "Incompatible version " << m_dist_version @@ -286,7 +305,8 @@ void tcp_connection::handle_connect(const boost::system::error_c str << "Cannot connect to node " << this->remote_nodename() << " at port " << m_peer_endpoint.port() << ": " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -306,7 +326,8 @@ void tcp_connection::handle_connect(const boost::system::error_c str << "Node name too long: " << this->local_nodename() << " [" << __FILE__ << ':' << __LINE__ << ']'; this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -343,7 +364,8 @@ void tcp_connection::handle_write_name(const boost::system::erro std::stringstream str; str << "Error writing auth challenge to node '" << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } m_state = CS_WAIT_STATUS; @@ -363,7 +385,8 @@ void tcp_connection::handle_read_status_header( std::stringstream str; str << "Error reading auth status from node '" << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -374,7 +397,8 @@ void tcp_connection::handle_read_status_header( std::stringstream str; str << "Node " << this->remote_nodename() << " rejected connection with reason: " << std::string(m_node_rd, len); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -402,7 +426,8 @@ void tcp_connection::handle_read_status_body( std::stringstream str; str << "Error reading auth status body from node '" << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -414,7 +439,8 @@ void tcp_connection::handle_read_status_body( std::stringstream str; str << "Error invalid auth status response '" << this->remote_nodename() << "': " << std::string(m_node_rd, 3); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -442,7 +468,8 @@ void tcp_connection::handle_read_challenge_header( std::stringstream str; str << "Error reading auth challenge from node '" << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -453,7 +480,8 @@ void tcp_connection::handle_read_challenge_header( std::stringstream str; str << "Error in auth status challenge node length " << this->remote_nodename() << " : " << m_expect_size; this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -479,7 +507,8 @@ void tcp_connection::handle_read_challenge_body( std::stringstream str; str << "Error reading auth challenge body from node '" << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -494,7 +523,8 @@ void tcp_connection::handle_read_challenge_body( std::stringstream str; str << "Error reading auth challenge tag '" << this->remote_nodename() << "': " << tag; this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -541,7 +571,8 @@ void tcp_connection::handle_write_challenge_reply(const boost::s std::stringstream str; str << "Error writing auth challenge reply to node '" << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } m_state = CS_WAIT_CHALLENGE_ACK; @@ -562,7 +593,8 @@ void tcp_connection::handle_read_challenge_ack_header( << this->remote_nodename() << "': " << (err == boost::asio::error::eof ? "Possibly bad cookie?" : err.message()); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -573,7 +605,8 @@ void tcp_connection::handle_read_challenge_ack_header( std::stringstream str; str << "Error in auth status challenge ack length " << this->remote_nodename() << " : " << m_expect_size; this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -602,7 +635,8 @@ void tcp_connection::handle_read_challenge_ack_body( std::stringstream str; str << "Error reading auth challenge ack body from node '" << this->remote_nodename() << "': " << err.message(); this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -624,7 +658,8 @@ void tcp_connection::handle_read_challenge_ack_body( std::stringstream str; str << "Error reading auth challenge ack body tag '" << this->remote_nodename() << "': " << tag; this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } @@ -635,7 +670,8 @@ void tcp_connection::handle_read_challenge_ack_body( std::stringstream str; str << "Authentication failure at node '" << this->remote_nodename() << '!'; this->handler()->on_connect_failure(this, str.str()); - m_socket.close(); + boost::system::error_code ec; + m_socket.close(ec); return; } diff --git a/include/eixx/marshal/binary.hpp b/include/eixx/marshal/binary.hpp index 2c13707..ebeb0d7 100644 --- a/include/eixx/marshal/binary.hpp +++ b/include/eixx/marshal/binary.hpp @@ -160,6 +160,6 @@ namespace std { } // namespace std -#include +#include #endif // _IMPL_BINARY_HPP_ diff --git a/include/eixx/marshal/binary.ipp b/include/eixx/marshal/binary.hxx similarity index 99% rename from include/eixx/marshal/binary.ipp rename to include/eixx/marshal/binary.hxx index 6fce5ff..65480bc 100644 --- a/include/eixx/marshal/binary.ipp +++ b/include/eixx/marshal/binary.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file binary.ipp +/// \file binary.hxx //---------------------------------------------------------------------------- /// \brief Implementation of binary class member functions. //---------------------------------------------------------------------------- diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index e79f957..610bdaf 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -617,6 +617,6 @@ namespace std { } } -#include +#include #endif diff --git a/include/eixx/marshal/eterm.ipp b/include/eixx/marshal/eterm.hxx similarity index 99% rename from include/eixx/marshal/eterm.ipp rename to include/eixx/marshal/eterm.hxx index cb2652f..4101f9c 100644 --- a/include/eixx/marshal/eterm.ipp +++ b/include/eixx/marshal/eterm.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file eterm.ipp +/// \file eterm.hxx //---------------------------------------------------------------------------- /// \brief Implementation of eterm member functions. //---------------------------------------------------------------------------- diff --git a/include/eixx/marshal/eterm_format.hpp b/include/eixx/marshal/eterm_format.hpp index a25c7e1..3ec3c4a 100644 --- a/include/eixx/marshal/eterm_format.hpp +++ b/include/eixx/marshal/eterm_format.hpp @@ -67,7 +67,7 @@ static void eformat(atom& mod, atom& fun, eterm& args, } // namespace marshal } // namespace eixx -#include +#include #endif // _EI_ETERM_FORMAT_HPP_ diff --git a/include/eixx/marshal/eterm_format.ipp b/include/eixx/marshal/eterm_format.hxx similarity index 100% rename from include/eixx/marshal/eterm_format.ipp rename to include/eixx/marshal/eterm_format.hxx diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 776978d..0511c27 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -353,6 +353,6 @@ namespace std { } // namespace std -#include +#include #endif // _IMPL_LIST_HPP_ diff --git a/include/eixx/marshal/list.ipp b/include/eixx/marshal/list.hxx similarity index 99% rename from include/eixx/marshal/list.ipp rename to include/eixx/marshal/list.hxx index 6aa1979..09e8aea 100644 --- a/include/eixx/marshal/list.ipp +++ b/include/eixx/marshal/list.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file list.ipp +/// \file list.hxx //---------------------------------------------------------------------------- /// \brief Implementation of the list member functions. //---------------------------------------------------------------------------- diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index 549f897..1c154a8 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -243,7 +243,7 @@ namespace std { } // namespace std -#include +#include #endif // _IMPL_PID_HPP_ diff --git a/include/eixx/marshal/pid.ipp b/include/eixx/marshal/pid.hxx similarity index 99% rename from include/eixx/marshal/pid.ipp rename to include/eixx/marshal/pid.hxx index 8093a4d..70e7349 100644 --- a/include/eixx/marshal/pid.ipp +++ b/include/eixx/marshal/pid.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file pid.ipp +/// \file pid.hxx //---------------------------------------------------------------------------- /// \brief Implementation of the epid member functions. //---------------------------------------------------------------------------- diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index 4495e18..e65573f 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -190,7 +190,7 @@ namespace std { } // namespace std -#include +#include #endif // _IMPL_PORT_HPP_ diff --git a/include/eixx/marshal/port.ipp b/include/eixx/marshal/port.hxx similarity index 99% rename from include/eixx/marshal/port.ipp rename to include/eixx/marshal/port.hxx index b01b2ed..c73e484 100644 --- a/include/eixx/marshal/port.ipp +++ b/include/eixx/marshal/port.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file port.ipp +/// \file port.hxx //---------------------------------------------------------------------------- /// \brief Implemention of port member functions. //---------------------------------------------------------------------------- diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index dfffde7..41502aa 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -242,7 +242,7 @@ namespace std { } // namespace std -#include +#include #endif // _IMPL_REF_HPP_ diff --git a/include/eixx/marshal/ref.ipp b/include/eixx/marshal/ref.hxx similarity index 99% rename from include/eixx/marshal/ref.ipp rename to include/eixx/marshal/ref.hxx index 2992b89..13f2352 100644 --- a/include/eixx/marshal/ref.ipp +++ b/include/eixx/marshal/ref.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file ref.ipp +/// \file ref.hxx //---------------------------------------------------------------------------- /// \brief Implementation of ref member functions. //---------------------------------------------------------------------------- diff --git a/include/eixx/marshal/tuple.hpp b/include/eixx/marshal/tuple.hpp index d93ec99..40f6e68 100644 --- a/include/eixx/marshal/tuple.hpp +++ b/include/eixx/marshal/tuple.hpp @@ -345,6 +345,6 @@ namespace std { } // namespace std -#include +#include #endif // _IMPL_TUPLE_HPP_ diff --git a/include/eixx/marshal/tuple.ipp b/include/eixx/marshal/tuple.hxx similarity index 99% rename from include/eixx/marshal/tuple.ipp rename to include/eixx/marshal/tuple.hxx index 9227320..c781888 100644 --- a/include/eixx/marshal/tuple.ipp +++ b/include/eixx/marshal/tuple.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file tuple.ipp +/// \file tuple.hxx //---------------------------------------------------------------------------- /// \brief Implementation of tuple's member functions. //---------------------------------------------------------------------------- diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index a7e279b..5c52264 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -52,7 +52,7 @@ using namespace boost::system::errc; * for use with BOOST ASIO. */ template> -struct async_queue : std::enable_shared_from_this> +struct async_queue : boost::enable_shared_from_this> { using queue_type = boost::lockfree::queue , boost::lockfree::capacity<1023>, @@ -91,11 +91,13 @@ struct async_queue : std::enable_shared_from_this> static const auto s_timeout = boost::system::errc::make_error_code(boost::system::errc::timed_out); + auto pthis = this->shared_from_this(); + // If we reached the batch size and queue has more data // to process - give up the time slice and reschedule the handler if (i == m_batch_size && !m_queue.empty()) { - m_io.post([this, h, repeat, repeat_count]() { - (*this->shared_from_this())(h, boost::asio::error::operation_aborted, repeat, repeat_count); + m_io.post([pthis, h, repeat, repeat_count]() { + (*pthis)(h, boost::asio::error::operation_aborted, repeat, repeat_count); }); return; } else if (!i && !h(value, s_timeout)) { @@ -111,9 +113,9 @@ struct async_queue : std::enable_shared_from_this> m_timer.cancel(); m_timer.expires_from_now(repeat); m_timer.async_wait( - [this, h, repeat, n] + [pthis, h, repeat, n] (const boost::system::error_code& ec) { - (*this->shared_from_this())(h, ec, repeat, n); + (*pthis)(h, ec, repeat, n); }); } } @@ -211,10 +213,11 @@ struct async_queue : std::enable_shared_from_this> boost::system::error_code ec; m_timer.cancel(ec); m_timer.expires_from_now(timeout); + auto pthis = this->shared_from_this(); m_timer.async_wait( - [this, &a_on_data, timeout, rep] + [pthis, &a_on_data, timeout, rep] (const boost::system::error_code& e) { - (*this->shared_from_this())(a_on_data, e, timeout, rep); + (*pthis)(a_on_data, e, timeout, rep); } ); } diff --git a/src/server.hpp b/src/server.hpp index 6c49760..064d130 100644 --- a/src/server.hpp +++ b/src/server.hpp @@ -27,7 +27,7 @@ template class channel_manager : private boost::noncopyable { public: - typedef std::shared_ptr channel_ptr; + using channel_ptr = boost::shared_ptr; /// Add the specified channel to the manager and start it. void start(channel_ptr c, bool a_connected = false) { @@ -68,8 +68,8 @@ template class server : private boost::noncopyable { public: - typedef Handler handler_type; - typedef std::shared_ptr > pointer; + using handler_type = Handler; + using pointer = boost::shared_ptr>; /// Construct the server to listen on the specified TCP address and port, and /// serve up files from the given directory. diff --git a/src/test_node.cpp b/src/test_node.cpp index cf57ac6..e83d110 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -25,8 +25,8 @@ void on_status(otp_node& a_node, const otp_connection* a_con, std::cerr << s_levels[a_level] << "| " << s << std::endl; } -std::shared_ptr g_io_server; -std::shared_ptr g_main; +boost::shared_ptr g_io_server; +boost::shared_ptr g_main; static atom g_rem_node; @@ -39,6 +39,9 @@ bool on_io_request(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) { static const eterm s_put_chars = eterm::format("{io_request,_,_,{put_chars,S}}"); + if (!a_msg) + return true; + varbind l_binding; if (s_put_chars.match(a_msg->msg(), &l_binding)) std::cerr << "I/O request from server: " @@ -53,6 +56,9 @@ bool on_main_msg(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) { static const eterm s_now_pattern = eterm::format("{rex, {N1, N2, N3}}"); static const eterm s_stop = atom("stop"); + if (!a_msg) + return true; + varbind l_binding; const eterm& l_msg = a_msg->msg(); @@ -142,22 +148,12 @@ int main(int argc, char* argv[]) { node.connect(on_connect, g_rem_node, reconnect_secs); - auto on_msg1 = [](auto& a_mailbox, auto& a_msg) - { - return on_io_request(a_mailbox, a_msg); - }; - - auto on_msg2 = [](auto& a_mailbox, auto& a_msg) - { - return on_main_msg(a_mailbox, a_msg); - }; - //otp_connection::connection_type* transport = a_con->transport(); - g_io_server->async_receive(on_msg1, std::chrono::milliseconds(-1), -1); + g_io_server->async_receive(on_io_request, std::chrono::milliseconds(-1), -1); - //node->send_rpc(self, a_con->remote_node(), atom("shell_default"), atom("ls"), - // list::make(), &io_server); - g_main->async_receive(on_msg2, std::chrono::seconds(5), -1); + //node.send_rpc(self, g_rem_node, atom("shell_default"), atom("ls"), + // list::make(), &g_io_server); + g_main->async_receive(on_main_msg, std::chrono::seconds(5), -1); node.run(); diff --git a/test/test_async_queue.cpp b/test/test_async_queue.cpp index cebe13e..07ef143 100644 --- a/test/test_async_queue.cpp +++ b/test/test_async_queue.cpp @@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE( test_async_queue_concurrent ) { boost::asio::io_service io; - std::shared_ptr> q(new async_queue(io, 128)); + boost::shared_ptr> q(new async_queue(io, 128)); boost::thread_group producer_threads; From ae349260ba4ba715eab121b07c5221e8ec5cf61d Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 18:03:19 -0500 Subject: [PATCH 080/185] Adjust Erlang cmake --- .travis.yml | 2 +- build-aux/FindErlang.cmake | 121 ++++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 57 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6ad8a1d..fcd158e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,7 +46,7 @@ before_script: script: - make bootstrap generator=make build=Debug - make - - make doc + - make doc > build/doc.log - make install - make test branches: diff --git a/build-aux/FindErlang.cmake b/build-aux/FindErlang.cmake index a6cf5b7..dd31321 100644 --- a/build-aux/FindErlang.cmake +++ b/build-aux/FindErlang.cmake @@ -14,73 +14,82 @@ # Erlang_ERTS_LIBRARY_DIR = /lib appended to Erlang_ERTS_DIR # -SET(ERLANG_BIN_PATH - $ENV{ERLANG_HOME}/bin - /opt/bin - /sw/bin - /usr/bin - /usr/local/bin - /opt/local/bin +IF (NOT Erlang_DIR) + SET(ERLANG_BIN_PATH + $ENV{ERLANG_HOME}/bin + /opt/bin + /sw/bin + /usr/bin + /usr/local/bin + /opt/local/bin + ) + FIND_PROGRAM(Erlang_ERL + NAMES erl + PATHS ${ERLANG_BIN_PATH} ) -FIND_PROGRAM(Erlang_ERL - NAMES erl - PATHS ${ERLANG_BIN_PATH} -) -FIND_PROGRAM(Erlang_COMPILE - NAMES erlc - PATHS ${ERLANG_BIN_PATH} -) + FIND_PROGRAM(Erlang_COMPILE + NAMES erlc + PATHS ${ERLANG_BIN_PATH} + ) -EXECUTE_PROCESS( - COMMAND erl -noshell -eval "io:format(\"~s\", [code:lib_dir()])" -s erlang halt - OUTPUT_VARIABLE Erlang_OTP_LIB_DIR -) + EXECUTE_PROCESS( + COMMAND erl -noshell -eval "io:format(\"~s\", [code:lib_dir()])" -s erlang halt + OUTPUT_VARIABLE Erlang_OTP_LIB_DIR + ) -EXECUTE_PROCESS( - COMMAND erl -noshell -eval "io:format(\"~s\", [code:root_dir()])" -s erlang halt - OUTPUT_VARIABLE Erlang_OTP_ROOT_DIR -) + EXECUTE_PROCESS( + COMMAND erl -noshell -eval "io:format(\"~s\", [code:root_dir()])" -s erlang halt + OUTPUT_VARIABLE Erlang_OTP_ROOT_DIR + ) + + EXECUTE_PROCESS( + COMMAND + erl -noshell -eval "io:format(\"~s\", [code:lib_dir(erl_interface)])" -s erlang halt + OUTPUT_VARIABLE Erlang_EI_DIR + ) -EXECUTE_PROCESS( - COMMAND - erl -noshell -eval "io:format(\"~s\", [code:lib_dir(erl_interface)])" -s erlang halt - OUTPUT_VARIABLE Erlang_EI_DIR -) + EXECUTE_PROCESS( + COMMAND + erl -noshell -eval "io:format(\"~s\", [erlang:system_info(otp_release)])" -s erlang halt + OUTPUT_VARIABLE Erlang_OTP_VERSION + ) -MESSAGE(STATUS "Using OTP lib: ${Erlang_OTP_LIB_DIR} - found") + MESSAGE(STATUS "Using Erlang OTP: ${Erlang_OTP_ROOT_DIR} - found OTP version ${Erlang_OTP_VERSION}") -EXECUTE_PROCESS( - COMMAND ls ${Erlang_OTP_ROOT_DIR} - COMMAND grep erts - COMMAND sort -n - COMMAND tail -1 - COMMAND tr -d \n - OUTPUT_VARIABLE Erlang_ERTS_DIR -) + EXECUTE_PROCESS( + COMMAND ls ${Erlang_OTP_ROOT_DIR} + COMMAND grep erts + COMMAND sort -n + COMMAND tail -1 + COMMAND tr -d \n + OUTPUT_VARIABLE Erlang_ERTS_DIR + ) -MESSAGE(STATUS "Using erl_interface version: ${Erlang_EI_DIR}") -MESSAGE(STATUS "Using erts version: ${Erlang_ERTS_DIR}") + MESSAGE(STATUS "Using erl_interface version: ${Erlang_EI_DIR}") + MESSAGE(STATUS "Using erts version: ${Erlang_ERTS_DIR}") -SET(Erlang_EI_DIR ${Erlang_EI_DIR} CACHE STRING "Erlang EI Dir") -SET(Erlang_EI_INCLUDE_DIR ${Erlang_OTP_ROOT_DIR}/usr/include CACHE STRING "Erlang EI Include Dir") -SET(Erlang_EI_LIBRARY_DIR ${Erlang_OTP_ROOT_DIR}/usr/lib CACHE STRING "Erlang EI Libary Dir") -SET(Erlang_EI_LIBRARIES ei CACHE STRING "Erlang EI Libraries") + SET(Erlang_EI_DIR ${Erlang_EI_DIR} CACHE STRING "Erlang EI Dir") + SET(Erlang_EI_INCLUDE_DIR ${Erlang_OTP_ROOT_DIR}/usr/include CACHE STRING "Erlang EI Include Dir") + SET(Erlang_EI_LIBRARY_DIR ${Erlang_OTP_ROOT_DIR}/usr/lib CACHE STRING "Erlang EI Libary Dir") + SET(Erlang_EI_LIBRARIES ei CACHE STRING "Erlang EI Libraries") -SET(Erlang_DIR ${Erlang_OTP_ROOT_DIR} CACHE STRING "Erlang Root Dir") -SET(Erlang_ERTS_DIR ${Erlang_OTP_ROOT_DIR}/${Erlang_ERTS_DIR}) -SET(Erlang_ERTS_INCLUDE_DIR ${Erlang_OTP_ROOT_DIR}/${Erlang_ERTS_DIR}/include) -SET(Erlang_ERTS_LIBRARY_DIR ${Erlang_OTP_ROOT_DIR}/${Erlang_ERTS_DIR}/lib) + SET(Erlang_DIR ${Erlang_OTP_ROOT_DIR} CACHE STRING "Erlang Root Dir") + SET(Erlang_ERTS_DIR ${Erlang_OTP_ROOT_DIR}/${Erlang_ERTS_DIR}) + SET(Erlang_ERTS_INCLUDE_DIR ${Erlang_OTP_ROOT_DIR}/${Erlang_ERTS_DIR}/include) + SET(Erlang_ERTS_LIBRARY_DIR ${Erlang_OTP_ROOT_DIR}/${Erlang_ERTS_DIR}/lib) -FIND_PROGRAM(Erlang_ARCHIVE - NAMES zip - PATHS ${ERLANG_BIN_PATH} -) -MARK_AS_ADVANCED( - Erlang_ERL - Erlang_COMPILE - Erlang_ARCHIVE + FIND_PROGRAM(Erlang_ARCHIVE + NAMES zip + PATHS ${ERLANG_BIN_PATH} + ) + MARK_AS_ADVANCED( + Erlang_ERL + Erlang_COMPILE + Erlang_ARCHIVE # Erlang_EI_DIR # Erlang_EI_INCLUDE_DIR # Erlang_EI_LIBRARY_DIR -) + ) + +ENDIF(NOT Erlang_DIR) From e37c461d5c433d85db3d71bb0f6313d1cb922877 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 18:07:54 -0500 Subject: [PATCH 081/185] Move files --- LICENSE.header => build-aux/LICENSE.header | 0 license.sh => build-aux/license.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename LICENSE.header => build-aux/LICENSE.header (100%) rename license.sh => build-aux/license.sh (100%) diff --git a/LICENSE.header b/build-aux/LICENSE.header similarity index 100% rename from LICENSE.header rename to build-aux/LICENSE.header diff --git a/license.sh b/build-aux/license.sh similarity index 100% rename from license.sh rename to build-aux/license.sh From 94f210d3615a55a11553f8e9b6e82ba19b52bbce Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 18:14:46 -0500 Subject: [PATCH 082/185] Fix Travis OTP release version --- .travis.yml | 3 +++ include/eixx/marshal/atom.hpp | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index fcd158e..e8c5121 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,8 @@ language: cpp compiler: g++ +language: erlang +otp_release: + - 18.1 addons: apt: sources: diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 34b3d16..ec23af8 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -129,8 +129,8 @@ class atom const char *s0 = s; int len; switch (get8(s)) { - case ERL_ATOM_EXT: len = get16be(s); break; - case ERL_SMALL_ATOM_EXT: len = get8(s); break; + case ERL_ATOM_EXT: len = get16be(s); break; + case ERL_SMALL_ATOM_EXT: len = get8(s); break; default: throw err_decode_exception("Error decoding atom", idx); } m_index = atom_table().lookup(std::string(s, len)); From b885652dac4b686a28fbb08ce5eb988533e68a99 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 17 Jan 2016 18:28:05 -0500 Subject: [PATCH 083/185] Install missing *.hxx files --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f928287..292a1a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,7 +188,7 @@ add_subdirectory(${CMAKE_SOURCE_DIR}/test) install( DIRECTORY ${CMAKE_SOURCE_DIR}/include/${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/include - FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" PATTERN "*.ipp" PATTERN "*.x??" + FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" PATTERN "*.hxx" ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/config.h From 3857f66aa9c6f2c735ec46a9ee96f70496fdc397 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 18 Jan 2016 18:12:15 -0500 Subject: [PATCH 084/185] Implement no allocation in 0-sized lists --- TODO | 11 +++++- include/eixx/marshal/alloc_base.hpp | 7 +++- include/eixx/marshal/list.hpp | 49 ++++++++++++++++++++---- include/eixx/marshal/list.hxx | 23 +++++++++--- test/test_eterm_refc.cpp | 58 ++++++++++++++++++++++------- 5 files changed, 120 insertions(+), 28 deletions(-) diff --git a/TODO b/TODO index 8bffbaa..f1982b4 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,12 @@ 1. Check serialization of long: -6478876429381754229 2. Check encoding binary encoding of: ["ecg",-6478876429381754229,Pid,"example_core",29633] -3. Optimize an empty list not to allocate space. See commit 7e52873a +3. Change internal representatino of eterm, so that the refcount is moved from blob_t to + eterm itself, so the layout of eterm would be the following: + a. change eterm_type's storage: + enum eterm_type : char; + b. change eterm: + struct eterm { + eterm_type m_type; + atomic m_rc; + union vartype {} m_data; + } diff --git a/include/eixx/marshal/alloc_base.hpp b/include/eixx/marshal/alloc_base.hpp index 2daa6bf..65f4ad2 100644 --- a/include/eixx/marshal/alloc_base.hpp +++ b/include/eixx/marshal/alloc_base.hpp @@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include namespace eixx { namespace marshal { @@ -88,9 +89,13 @@ namespace marshal { T* m_data; ~blob() { - this->deallocate(m_data, m_size); + if (m_data) + this->deallocate(m_data, m_size); } + /// This is needed in order to allow blobs to be hosted inside + /// std::unique_ptr: + template friend struct std::default_delete; public: blob(const Alloc& a = Alloc()) : base_t(a), m_rc(1), m_size(0), m_data(NULL) diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 0511c27..9a5ba4a 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -56,6 +56,13 @@ class list : protected alloc_base, Alloc> { typedef alloc_base base_t; struct header_t { + header_t() {} + header_t(std::nullptr_t) + : initialized(true) + , alloc_size (0) + , size (0) + , tail (nullptr) + {} bool initialized; unsigned int alloc_size; unsigned int size; @@ -67,6 +74,18 @@ class list : protected alloc_base, Alloc> { blob_t* m_blob; + /// Returns a pointer to a singleton empty list + static blob_t* empty_list() { + auto creator = []() { + auto p = new blob_t(sizeof(header_t)); + auto h = reinterpret_cast(p->data()); + new (h) header_t(nullptr); + return p; + }; + static std::unique_ptr s_empty(creator()); + return s_empty.get(); + } + header_t* header() { BOOST_ASSERT(m_blob); return reinterpret_cast(m_blob->data()); } @@ -78,7 +97,7 @@ class list : protected alloc_base, Alloc> { cons_t* tail() { return header()->tail; } void release() { - if (!m_blob) + if (!m_blob || m_blob == empty_list()) return; if (m_blob->release(false)) { header_t* l_header = header(); @@ -115,15 +134,26 @@ class list : protected alloc_base, Alloc> { , m_blob(NULL) {} + /// Construct an NIL list (initialized list with no elements) + explicit list(std::nullptr_t) : m_blob(empty_list()) {} + + /// Construct a list with a given estimated size. + /// + /// When a_estimated_size is 0, an empty initialized list is created. Otherwise, + /// the list is not initialized. explicit list(int a_estimated_size, const Alloc& alloc = Alloc()) : base_t(alloc) - , m_blob(new blob_t(sizeof(header_t) + a_estimated_size*sizeof(cons_t), alloc)) { - header_t* l_header = header(); - l_header->initialized = a_estimated_size == 0; - l_header->alloc_size = a_estimated_size; - l_header->size = 0; - l_header->tail = NULL; + if (a_estimated_size == 0) + m_blob = empty_list(); + else { + m_blob = new blob_t(sizeof(header_t) + a_estimated_size*sizeof(cons_t), alloc); + header_t* hdr = header(); + hdr->initialized = a_estimated_size == 0; + hdr->alloc_size = a_estimated_size; + hdr->size = 0; + hdr->tail = NULL; + } } list(const list& a) : base_t(a.get_allocator()), m_blob(a.m_blob) { @@ -174,7 +204,10 @@ class list : protected alloc_base, Alloc> { * Closes the list. * A list must be closed before it can be copied or included into other terms. */ - void close() { header()->initialized = true; } + void close() { + if (!m_blob || m_blob == empty_list()) return; + header()->initialized = true; + } /// Return list length. This method has O(1) complexity. size_t length() const { return m_blob ? header()->size : 0; } diff --git a/include/eixx/marshal/list.hxx b/include/eixx/marshal/list.hxx index 09e8aea..3f2f8fa 100644 --- a/include/eixx/marshal/list.hxx +++ b/include/eixx/marshal/list.hxx @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -/// \file list.hxx +/// \file list.ipp //---------------------------------------------------------------------------- /// \brief Implementation of the list member functions. //---------------------------------------------------------------------------- @@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***** END LICENSE BLOCK ***** */ +#pragma once #include #include @@ -37,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include -namespace eixx { +namespace eixx { namespace marshal { template @@ -82,6 +83,12 @@ list::list(const cons_t* a_head, int a_len, const Alloc& alloc) } else throw err_bad_argument("List of negative length!"); + // If this is an empty list - no allocation is needed + if (alloc_size == 0) { + m_blob = empty_list(); + return; + } + m_blob = new blob_t(sizeof(header_t) + alloc_size*sizeof(cons_t), alloc); header_t* l_header = header(); l_header->initialized = true; @@ -102,12 +109,18 @@ list::list(const cons_t* a_head, int a_len, const Alloc& alloc) template list::list(const char *buf, int& idx, size_t size, const Alloc& a_alloc) - throw(err_decode_exception) : base_t(a_alloc) + throw(err_decode_exception) : base_t(a_alloc) { int arity; if (ei_decode_list_header(buf, &idx, &arity) < 0) err_decode_exception("Error decoding list header", idx); -// TODO: optimize for an empty list!!! + + // If this is an empty list - no allocation is needed + if (arity == 0) { + m_blob = empty_list(); + return; + } + m_blob = new blob_t(sizeof(header_t) + arity*sizeof(cons_t), a_alloc); header_t* l_header = header(); l_header->initialized = true; @@ -274,4 +287,4 @@ std::ostream& list::dump(std::ostream& out, const varbind* vars) c } } // namespace marshal -} // namespace eixx +} // namespace eixx \ No newline at end of file diff --git a/test/test_eterm_refc.cpp b/test/test_eterm_refc.cpp index b57dd7c..b58d606 100644 --- a/test/test_eterm_refc.cpp +++ b/test/test_eterm_refc.cpp @@ -24,13 +24,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include "test_alloc.hpp" #include +#include using namespace eixx; using eixx::marshal::eterm; +using eixx::marshal::list; + +static int g_alloc_count; template struct counted_alloc : public std::allocator { - static int count; counted_alloc() {} counted_alloc(const counted_alloc& a) {} @@ -49,33 +52,36 @@ struct counted_alloc : public std::allocator { void construct(pointer p, const T& value) { ::new((void*)p) T(value); } - + pointer allocate(size_t sz) { - count++; + ++g_alloc_count; return static_cast(::operator new(sz * sizeof(T))); } void deallocate(pointer p, size_t sz) { - count--; + --g_alloc_count; ::operator delete(p); } void destroy(pointer __p) { __p->~T(); } }; -template -int counted_alloc::count = 0; - BOOST_AUTO_TEST_CASE( test_refc_format ) { typedef counted_alloc my_alloc; my_alloc alloc; + + list lst(nullptr); // Allocates static global empty list + BOOST_CHECK_EQUAL(2, g_alloc_count); + { for (int i=0; i < 10; i++) { - eterm term = eterm::format(alloc, + BOOST_CHECK_EQUAL(2, g_alloc_count); + eterm term = eterm::format(alloc, "[~i, [{~s, ~i}, {~a, ~i}], {~f, ~i}, ~a]", 1, "ab", 2, "xx", 3, 2.1, 10, "abc"); - BOOST_REQUIRE_EQUAL(LIST, term.type()); + BOOST_CHECK_EQUAL(LIST, term.type()); + BOOST_CHECK_EQUAL(2+(6*2), g_alloc_count); for (int j=0; j <= 10; j++) eterm term = eterm::format(alloc, @@ -83,10 +89,10 @@ BOOST_AUTO_TEST_CASE( test_refc_format ) 1, "ab", 2, "xx", 3, 2.1, 10, "abc"); } } - BOOST_REQUIRE_EQUAL(0, my_alloc::count); + BOOST_CHECK_EQUAL(2, g_alloc_count); } -BOOST_AUTO_TEST_CASE( test_pool_format ) +BOOST_AUTO_TEST_CASE( test_refc_pool_format ) { typedef boost::pool_allocator my_alloc; my_alloc alloc; @@ -95,14 +101,40 @@ BOOST_AUTO_TEST_CASE( test_pool_format ) eterm term = eterm::format(alloc, "[~i, [{~s, ~i}, {~a, ~i}], {~f, ~i}, ~a]", 1, "ab", 2, "xx", 3, 2.1, 10, "abc"); - BOOST_REQUIRE_EQUAL(LIST, term.type()); + BOOST_CHECK_EQUAL(LIST, term.type()); for (int j=0; j <= 10; j++) { eterm term = eterm::format(alloc, "{~i, [{~s, ~i}, {~a, ~i}], {~f, ~i}, ~a}", 1, "ab", 2, "xx", 3, 2.1, 10, "abc"); - BOOST_REQUIRE_EQUAL(TUPLE, term.type()); + BOOST_CHECK_EQUAL(TUPLE, term.type()); } } } } + +BOOST_AUTO_TEST_CASE( test_refc_list ) +{ + typedef counted_alloc my_alloc; + my_alloc alloc; + + list lst(nullptr); // Allocates static global empty list + BOOST_CHECK_EQUAL(2, g_alloc_count); + + { + eterm term = list({1, 2, 3}, alloc); + BOOST_CHECK_EQUAL(4, g_alloc_count); // 1 for blob_t, 1 for blob's data + auto term2 = term; + BOOST_CHECK_EQUAL(4, g_alloc_count); + } + BOOST_CHECK_EQUAL(2, g_alloc_count); + + { + // Construct a NIL list + eterm term = list(nullptr); + BOOST_CHECK_EQUAL(2, g_alloc_count); + auto term2 = term; + BOOST_CHECK_EQUAL(2, g_alloc_count); + } + BOOST_CHECK_EQUAL(2, g_alloc_count); +} \ No newline at end of file From d3838d67ad64eed316605784ef9a5f4d51bb8835 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 19 Jan 2016 09:41:49 -0500 Subject: [PATCH 085/185] Update README --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0ab0f34..92571fa 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ ENV:BOOST_ROOT=/opt/pkg/boost/current ENV:BOOST_LIBRARYDIR=/opt/pkg/boost/current/gcc/lib PKG_ROOT_DIR=/opt/pkg ``` -Run: +* Run: ``` $ make bootstrap [toolchain=gcc|clang] [build=Debug|Release] \ [generator=make|ninja] [prefix=/usr/local] [verbose=true] @@ -85,12 +85,14 @@ $ make install # Default install path is /usr/local After running `make bootstrap` two local links are created `build` and `inst` pointing to build and installation directories. -If you need to do a full cleanup of the current build and rerun bootstrap with +* To do a full cleanup of the current build and rerun bootstrap with previously chosen options, do: ``` $ make distclean -$ make rebootstrap +$ make rebootstrap [toolchain=gcc|clang] [build=Debug|Release] ``` +Note that the `rebootstrap` command remembers previous bootstrap options, but +if you give it arguments they will override the old ones. ### Author ### @@ -236,7 +238,7 @@ Test distributed transport: msg={io_request,#Pid,#Pid, {put_chars,<<"This is a test string">>}}} -The message above is a result of the on_connect() handler in test_node.cpp +The message above is a result of the `on_connect()` handler in `test_node.cpp` issuing an rpc call to the abc@fc12 node of `io:put_chars("This is a test string")'. This the call selects a locally registered process called 'io_server' as the group leader for this rpc call, the I/O output is sent From c06ceafd888c62a1d5d74cc22b7465af9bd40c74 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 19 Jan 2016 10:22:08 -0500 Subject: [PATCH 086/185] Change perf test to std::alloc --- test/CMakeLists.txt | 4 ++-- test/test_async_queue.cpp | 2 +- test/test_eterm.cpp | 2 +- test/test_perf.cpp | 17 ++++++++++++++++- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 336fa9e..bd96aa6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,9 +17,9 @@ target_compile_definitions(test-eterm PRIVATE -DBOOST_TEST_DYN_LINK) target_include_directories(test-eterm PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries( test-eterm + boost_unit_test_framework eixx ${Erlang_EI_LIBRARIES} - boost_unit_test_framework ${Boost_LIBRARIES} boost_system ) @@ -27,9 +27,9 @@ target_link_libraries( add_executable(test-connect test_async_queue.cpp) target_link_libraries( test-connect + boost_unit_test_framework eixx ${Erlang_EI_LIBRARIES} - boost_unit_test_framework ${Boost_LIBRARIES} ) diff --git a/test/test_async_queue.cpp b/test/test_async_queue.cpp index 07ef143..d148f59 100644 --- a/test/test_async_queue.cpp +++ b/test/test_async_queue.cpp @@ -36,8 +36,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include +#include #include -#include #include #include diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 3c007a9..8babb44 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define BOOST_TEST_MODULE test_eterm -#include +#include #include "test_alloc.hpp" #include #include diff --git a/test/test_perf.cpp b/test/test_perf.cpp index eea9ced..4c86f66 100644 --- a/test/test_perf.cpp +++ b/test/test_perf.cpp @@ -1,4 +1,5 @@ -#include "test_alloc.hpp" +#include +//#include "test_alloc.hpp" // Uses boost::pool_alloc, which does much worse #include #include #include @@ -154,6 +155,20 @@ int main(int argc, char* argv[]) { iterations *= 10; } + { + iterations /= 10; + size_t size = 0; + for (int j=0, e = iterations; j < e; j++) { + auto x = tuple{am_md, xchg, instr, + list{tuple{am_q, + list{tuple{1.2345, 100000}}, + list{tuple{1.2355, 200000}}}}}; + size += x.encode_size(); + } + t.sample("Create2 speed", true, size); + iterations *= 10; + } + return 0; } From 654cc27e65195b1f07623bf934f33f9f374c3db2 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 20 Jan 2016 00:06:04 -0500 Subject: [PATCH 087/185] Update perf test --- README.md | 22 ++++++++++++++++++++++ test/test_perf.cpp | 40 +++++++++++++++++++++++++--------------- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 92571fa..100562d 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,28 @@ varbind binding; if (value.match(s_pattern, &binding)) std::cout << "Value of variable A: " << binding["A"].to_string() << std::endl; ``` +Erlang terms manipulation is pretty efficient. Creation/copying times of polymorphic +eterm's are shown below (project compiled in the `release` mode): +``` +$ build/test/test-perf + 1000000 iterations + Integer | latency: 6ns, speed: 150015001/s + Double | latency: 3ns, speed: 300030003/s + Bool | latency: 3ns, speed: 299940011/s + String | latency: 50ns, speed: 20000000/s + Atom1 | latency: 30ns, speed: 33333333/s + Atom2 | latency: 30ns, speed: 33333333/s + Binary1 | latency: 50ns, speed: 20000000/s + Binary2 | latency: 6ns, speed: 150015001/s + Tuple1 | latency: 73ns, speed: 13636425/s + Tuple2 | latency: 20ns, speed: 50000000/s + List1 | latency: 76ns, speed: 13043421/s + List2 | latency: 23ns, speed: 42857755/s + Apply speed | latency: 1173ns, speed: 852272/s + Apply/Create speed | latency: 953ns, speed: 1048951/s + Nested lists/tuples (1) speed | latency: 533ns, speed: 1874976/s + Nested lists/tuples (2) speed | latency: 466ns, speed: 2142841/s +``` Aside from providing functionality that allows to manipulate Erlang terms, this library implements Erlang distributed transport that allows a C++ program to connect to an Erlang node, exchange messages, make RPC calls, and receive I/O requests. diff --git a/test/test_perf.cpp b/test/test_perf.cpp index 4c86f66..aacf8b0 100644 --- a/test/test_perf.cpp +++ b/test/test_perf.cpp @@ -5,10 +5,19 @@ #include #include -using namespace eixx; +/// Prevent variable optimization by the compiler +#ifdef _MSC_VER +#pragma optimize("", off) +template void dont_optimize_var(T&& v) { v = v; } +#pragma optimize("", on) +#else +template void dont_optimize_var(T&& v) { asm volatile("":"+r" (v)); } +#endif -int iterations=200000; +using namespace eixx; +int iterations=1000000; +size_t g_size = 0; class timer { struct rusage start, end; void begin() { getrusage(RUSAGE_THREAD, &start); } @@ -23,10 +32,12 @@ class timer { end.ru_stime.tv_sec - start.ru_stime.tv_sec) + (double)(end.ru_utime.tv_usec - start.ru_utime.tv_usec + end.ru_stime.tv_usec - start.ru_stime.tv_usec)/1000000.0; + g_size += out; // out is used merely to trick the optimizer - printf("%30s | latency: %7.3fus, speed: %9ld/s%s", title, - 1000000.0*diff/iterations, diff > 0 ? long((double)iterations / diff) : 0, + printf("%30s | latency: %5ldns, speed: %9ld/s%s", title, + long(1000000000.0*diff/iterations), + diff > 0 ? long((double)iterations / diff) : 0, out == 0 ? "\n" : " \n"); if (restart) begin(); @@ -48,19 +59,19 @@ int main(int argc, char* argv[]) { size_t size = 0; for (int j=0; j < iterations; j++) - { size += eterm(1).encode_size(); } + { size += eterm(j).encode_size(); } t.sample("Integer", true, size); for (int j=0; j < iterations; j++) - { eterm(1.0).encode_size(); } + { size += eterm((double)j).encode_size(); } t.sample("Double", true, size); for (int j=0; j < iterations; j++) - { eterm(true).encode_size(); } + { size += eterm(j&1).encode_size(); } t.sample("Bool", true, size); for (int j=0; j < iterations; j++) - { eterm("test").encode_size(); } + { size += eterm("test").encode_size(); } t.sample("String", true, size); for (int j=0; j < iterations; j++) - { atom("test").encode_size(); } + { size += atom("test").encode_size(); } t.sample("Atom1", true, size); { atom a("test"); @@ -120,7 +131,6 @@ int main(int argc, char* argv[]) { atom instr("EUR/USD"); t.restart(); { - size_t size = 0; for (int j=0; j < iterations; j++) { auto x = s_md1.apply({{am_Xchg, xchg}, {am_Instr, instr}, {am_BPx, 1.2345}, {am_BQty, 100000}, @@ -130,7 +140,6 @@ int main(int argc, char* argv[]) { t.sample("Apply speed", true, size); } { - size_t size = 0; for (int j=0; j < iterations; j++) { auto x = s_md2.apply({{am_Xchg, xchg}, {am_Instr, instr}, {am_L1, list::make(tuple::make(1.2345, 100000))}, @@ -143,7 +152,6 @@ int main(int argc, char* argv[]) { atom am_q ("q"); { iterations /= 10; - size_t size = 0; for (int j=0, e = iterations; j < e; j++) { auto x = tuple::make(am_md, xchg, instr, list::make(tuple::make(am_q, @@ -151,13 +159,12 @@ int main(int argc, char* argv[]) { list::make(tuple::make(1.2355, 200000))))); size += x.encode_size(); } - t.sample("Create speed", true, size); + t.sample("Nested lists/tuples (1) speed", true, size); iterations *= 10; } { iterations /= 10; - size_t size = 0; for (int j=0, e = iterations; j < e; j++) { auto x = tuple{am_md, xchg, instr, list{tuple{am_q, @@ -165,10 +172,13 @@ int main(int argc, char* argv[]) { list{tuple{1.2355, 200000}}}}}; size += x.encode_size(); } - t.sample("Create2 speed", true, size); + t.sample("Nested lists/tuples (2) speed", true, size); iterations *= 10; } + if (g_size == 0) + std::cerr << "No iterations performed!" << std::endl; + return 0; } From 22fdb067bee1438baeff2d86dedf171b6b2f7968 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 20 Jan 2016 10:32:26 -0500 Subject: [PATCH 088/185] Fix exporting cached variables --- bootstrap.mk | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bootstrap.mk b/bootstrap.mk index 1a55f08..da80f4c 100644 --- a/bootstrap.mk +++ b/bootstrap.mk @@ -125,15 +125,15 @@ bootstrap: | $(DIR) $(call makecmd) 2>&1 | tee $(DIR)/.cmake.bootstrap.log @[ ! -d build ] && ln -s $(DIR) build || true @ln -s $(prefix) inst - @echo "make bootstrap $(MAKEOVERRIDES)" > $(DIR)/.bootstrap + @echo "make bootstrap $(MAKEOVERRIDES)" > $(DIR)/.bootstrap @cp $(DIR)/.bootstrap .build/ - @echo "PROJECT := $(PROJECT)" > $(DIR)/cache.mk - @echo "VERSION := $(VERSION)" >> $(DIR)/cache.mk - @echo "OPT_FILE := $(abspath $(OPT_FILE))" >> $(DIR)/cache.mk - @echo "generator := $(generator)" >> $(DIR)/cache.mk - @echo "build := $(BUILD)" >> $(DIR)/cache.mk - @echo "DIR := $(DIR)" >> $(DIR)/cache.mk - @echo "prefix := $(prefix)" >> $(DIR)/cache.mk + @echo "export PROJECT := $(PROJECT)" > $(DIR)/cache.mk + @echo "export VERSION := $(VERSION)" >> $(DIR)/cache.mk + @echo "export OPT_FILE := $(abspath $(OPT_FILE))" >> $(DIR)/cache.mk + @echo "export generator := $(generator)" >> $(DIR)/cache.mk + @echo "export build := $(BUILD)" >> $(DIR)/cache.mk + @echo "export DIR := $(DIR)" >> $(DIR)/cache.mk + @echo "export prefix := $(prefix)" >> $(DIR)/cache.mk $(DIR): @mkdir -p $@ From 16c6a5cfa47459fe459155969b0b4e6aced68d2f Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 21 Jan 2016 10:03:51 -0500 Subject: [PATCH 089/185] Fix makefiles --- CMakeLists.txt | 18 ++++++++++-------- src/CMakeLists.txt | 10 +++++++--- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 292a1a5..0acb7c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ if(WITH_ENUM_SERIALIZATION) endif() string(TOLOWER ${TOOLCHAIN} toolchain) -string(TOUPPER "${PROJECT_NAME}-${TOOLCHAIN}" BUILD_TYPE) +string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE) # Custom extensions include(${CMAKE_CURRENT_SOURCE_DIR}/build-aux/CMakeEx.txt) @@ -29,18 +29,13 @@ if("${toolchain}" STREQUAL "gcc") set(CMAKE_CXX_COMPILER "g++") add_definitions(-Wno-strict-aliasing -fopenmp -Wall) - if("${CMAKE_BUILD_TYPE}" STREQUAL "Release") + if("${CMAKE_BUILD_TYPE}" STREQUAL "release") add_definitions(-flto -funroll-loops -fomit-frame-pointer) # The following will omit all symbol information from the build: #add_definitions(-Wl,-s) #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s") endif() - - #if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release") - # add_definitions(-flto -funroll-loops -fomit-frame-pointer -Wl,-s) - # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s") - #endif() elseif("${toolchain}" STREQUAL "intel") set(CMAKE_C_COMPILER "icc") set(CMAKE_CXX_COMPILER "icpc") @@ -54,6 +49,11 @@ else() message(FATAL_ERROR "Invalid toolchain: ${TOOLCHAIN}") endif() +# Append "_d" to the library when doing debug build +if (CMAKE_BUILD_TYPE STREQUAL "debug") + set(LIB_SUFFIX "_d") +endif() + # Note: explicit c++14 definitions done in CMakeInit.txt. # Alternative is to set for each target: # target_compile_features(${PROJECT_NAME} PRIVATE cxx_lambda_init_captures) @@ -65,7 +65,9 @@ add_definitions( -DBOOST_SYSTEM_NO_DEPRECATED ) -message(STATUS "${ClrBold}Configuring for the ${TOOLCHAIN} toolchain${ClrReset}") +message(STATUS "Configuring for the " + "${BoldMagenta}${TOOLCHAIN}${ClrReset} toolchain " + "${BoldMagenta}${CMAKE_BUILD_TYPE}${ClrReset} build") #------------------------------------------------------------------------------- # Policies diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db3a30e..b9b3eb4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,9 +11,13 @@ add_library(${PROJECT_NAME}_static STATIC ${EIXX_SRCS}) set_target_properties(${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) target_link_libraries(${PROJECT_NAME} ${EIXX_LIBS}) -if (${BUILD_TYPE} STREQUAL "Debug") - set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX "-d.so") - set_target_properties(${PROJECT_NAME}_static PROPERTIES SUFFIX "-d.so") +if (${CMAKE_BUILD_TYPE} STREQUAL "debug") + set_target_properties(${PROJECT_NAME} PROPERTIES + DEBUG_POSTFIX "${LIB_SUFFIX}" + RELEASE_POSTFIX "") + set_target_properties(${PROJECT_NAME}_static PROPERTIES + DEBUG_POSTFIX "${LIB_SUFFIX}" + RELEASE_POSTFIX "") endif() set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) From 81d8a7047f112af0b8e298afe54e69bc64937827 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Fri, 22 Jan 2016 23:14:57 -0500 Subject: [PATCH 090/185] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 100562d..bd21a4e 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,10 @@ $ build/test/test-perf Nested lists/tuples (1) speed | latency: 533ns, speed: 1874976/s Nested lists/tuples (2) speed | latency: 466ns, speed: 2142841/s ``` +The last four tests illustrate various ways of creating nested terms with tuples, +lists and other types. The other tests illustrate creation times of primitive +eterm types. + Aside from providing functionality that allows to manipulate Erlang terms, this library implements Erlang distributed transport that allows a C++ program to connect to an Erlang node, exchange messages, make RPC calls, and receive I/O requests. From b2bd88bf78b99cf5504470043de91098a65f7c04 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sat, 23 Jan 2016 08:07:48 -0500 Subject: [PATCH 091/185] Add pattern match speed tests --- README.md | 24 +++++++++++++----------- test/test_perf.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 100562d..5605fa5 100644 --- a/README.md +++ b/README.md @@ -141,20 +141,22 @@ $ build/test/test-perf 1000000 iterations Integer | latency: 6ns, speed: 150015001/s Double | latency: 3ns, speed: 300030003/s - Bool | latency: 3ns, speed: 299940011/s - String | latency: 50ns, speed: 20000000/s - Atom1 | latency: 30ns, speed: 33333333/s - Atom2 | latency: 30ns, speed: 33333333/s - Binary1 | latency: 50ns, speed: 20000000/s + Bool | latency: 3ns, speed: 300030003/s + String | latency: 56ns, speed: 17646955/s + Atom1 | latency: 33ns, speed: 30000300/s + Atom2 | latency: 36ns, speed: 27272479/s + Binary1 | latency: 46ns, speed: 21428877/s Binary2 | latency: 6ns, speed: 150015001/s - Tuple1 | latency: 73ns, speed: 13636425/s + Tuple1 | latency: 73ns, speed: 13636239/s Tuple2 | latency: 20ns, speed: 50000000/s - List1 | latency: 76ns, speed: 13043421/s + List1 | latency: 73ns, speed: 13636239/s List2 | latency: 23ns, speed: 42857755/s - Apply speed | latency: 1173ns, speed: 852272/s - Apply/Create speed | latency: 953ns, speed: 1048951/s - Nested lists/tuples (1) speed | latency: 533ns, speed: 1874976/s - Nested lists/tuples (2) speed | latency: 466ns, speed: 2142841/s + Apply speed | latency: 1190ns, speed: 840336/s + Apply/Create speed | latency: 966ns, speed: 1034482/s + Nested lists/tuples (1) speed | latency: 566ns, speed: 1764695/s + Nested lists/tuples (2) speed | latency: 466ns, speed: 2142887/s + Simple pattern match (1) | latency: 33ns, speed: 30003000/s + Nested pattern match (2) | latency: 333ns, speed: 2999940/s ``` Aside from providing functionality that allows to manipulate Erlang terms, this library implements Erlang distributed transport that allows a C++ program to connect diff --git a/test/test_perf.cpp b/test/test_perf.cpp index aacf8b0..a570dbd 100644 --- a/test/test_perf.cpp +++ b/test/test_perf.cpp @@ -176,6 +176,39 @@ int main(int argc, char* argv[]) { iterations *= 10; } + { + static const eterm s_pattern = eterm::format("V"); + static atom am_var("V"); + if (!s_pattern.match(12345)) + std::cerr << "Expected match failed at line " << __LINE__ << std::endl;; + + iterations /= 10; + for (int j=0, e = iterations; j < e; j++) { + varbind binding; + if (s_pattern.match(12345, &binding)) + size++; + } + t.sample("Simple pattern match (1)", true, size); + iterations *= 10; + } + + { + static const eterm s_pattern = eterm::format("{error, [{abc, V}]}"); + static const eterm s_term = eterm::format("{error, [{abc, \"ok\"}]}"); + static atom am_var("V"); + if (!s_term.match(s_pattern)) + std::cerr << "Expected match failed at line " << __LINE__ << std::endl;; + + iterations /= 10; + for (int j=0, e = iterations; j < e; j++) { + varbind binding; + if (s_term.match(s_pattern, &binding)) + size++; + } + t.sample("Nested pattern match (2)", true, size); + iterations *= 10; + } + if (g_size == 0) std::cerr << "No iterations performed!" << std::endl; From ae618a43aa7e4d50668600a5794fa902fd96ad78 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 27 Jan 2016 07:44:11 -0500 Subject: [PATCH 092/185] Remove whitespace --- .gitignore | 1 + README.md | 39 +++++++++++++++++++-------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index bb64e26..258e0d7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ .cproject .kdev4/ .project +.cmake-args* build inst test/.kdev4/ diff --git a/README.md b/README.md index 2f0a9c5..d48875c 100644 --- a/README.md +++ b/README.md @@ -139,23 +139,23 @@ eterm's are shown below (project compiled in the `release` mode): ``` $ build/test/test-perf 1000000 iterations - Integer | latency: 6ns, speed: 150015001/s - Double | latency: 3ns, speed: 300030003/s - Bool | latency: 3ns, speed: 300030003/s - String | latency: 56ns, speed: 17646955/s - Atom1 | latency: 33ns, speed: 30000300/s - Atom2 | latency: 36ns, speed: 27272479/s - Binary1 | latency: 46ns, speed: 21428877/s - Binary2 | latency: 6ns, speed: 150015001/s - Tuple1 | latency: 73ns, speed: 13636239/s - Tuple2 | latency: 20ns, speed: 50000000/s - List1 | latency: 73ns, speed: 13636239/s - List2 | latency: 23ns, speed: 42857755/s - Apply speed | latency: 1190ns, speed: 840336/s - Apply/Create speed | latency: 966ns, speed: 1034482/s - Nested lists/tuples (1) speed | latency: 566ns, speed: 1764695/s - Nested lists/tuples (2) speed | latency: 466ns, speed: 2142887/s - Simple pattern match (1) | latency: 33ns, speed: 30003000/s + Integer | latency: 6ns, speed: 150015001/s + Double | latency: 3ns, speed: 300030003/s + Bool | latency: 3ns, speed: 300030003/s + String | latency: 56ns, speed: 17646955/s + Atom1 | latency: 33ns, speed: 30000300/s + Atom2 | latency: 36ns, speed: 27272479/s + Binary1 | latency: 46ns, speed: 21428877/s + Binary2 | latency: 6ns, speed: 150015001/s + Tuple1 | latency: 73ns, speed: 13636239/s + Tuple2 | latency: 20ns, speed: 50000000/s + List1 | latency: 73ns, speed: 13636239/s + List2 | latency: 23ns, speed: 42857755/s + Apply speed | latency: 1190ns, speed: 840336/s + Apply/Create speed | latency: 966ns, speed: 1034482/s + Nested lists/tuples (1) speed | latency: 566ns, speed: 1764695/s + Nested lists/tuples (2) speed | latency: 466ns, speed: 2142887/s + Simple pattern match (1) | latency: 33ns, speed: 30003000/s Nested pattern match (2) | latency: 333ns, speed: 2999940/s ``` The last four tests illustrate various ways of creating nested terms with tuples, @@ -197,7 +197,7 @@ void on_message(otp_mailbox& a_mbox, boost::system::error_code& ec) { } } } - + // Schedule next async receive of a message (can also provide a timeout). a_mbox.async_receive(&on_message); } @@ -283,5 +283,4 @@ registered on the C++ node: #DistMsg{ type=REG_SEND, cntrl={6,#Pid,'',main}, - msg="This is a test!"} - + msg="This is a test!"} \ No newline at end of file From ee4918943309d53f193f5d9f028552bc7ac66d63 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 18 Feb 2016 15:24:08 -0500 Subject: [PATCH 093/185] Remove tabs --- include/eixx/marshal/am.hpp | 46 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/include/eixx/marshal/am.hpp b/include/eixx/marshal/am.hpp index 1a85c3c..f8698ff 100644 --- a/include/eixx/marshal/am.hpp +++ b/include/eixx/marshal/am.hpp @@ -40,28 +40,28 @@ namespace eixx { // Constant global atom values - const atom am_ANY_ = atom("_"); - extern const atom am_badarg; - extern const atom am_badrpc; - extern const atom am_call; - extern const atom am_cast; - extern const atom am_erlang; - extern const atom am_error; - extern const atom am_false; - extern const atom am_format; - extern const atom am_gen_cast; - extern const atom am_io_lib; - extern const atom am_latin1; - extern const atom am_noconnection; - extern const atom am_noproc; - extern const atom am_normal; - extern const atom am_ok; - extern const atom am_request; - extern const atom am_rex; - extern const atom am_rpc; - extern const atom am_true; - extern const atom am_undefined; - extern const atom am_unsupported; - extern const atom am_user; + const atom am_ANY_ = atom("_"); + extern const atom am_badarg; + extern const atom am_badrpc; + extern const atom am_call; + extern const atom am_cast; + extern const atom am_erlang; + extern const atom am_error; + extern const atom am_false; + extern const atom am_format; + extern const atom am_gen_cast; + extern const atom am_io_lib; + extern const atom am_latin1; + extern const atom am_noconnection; + extern const atom am_noproc; + extern const atom am_normal; + extern const atom am_ok; + extern const atom am_request; + extern const atom am_rex; + extern const atom am_rpc; + extern const atom am_true; + extern const atom am_undefined; + extern const atom am_unsupported; + extern const atom am_user; } // namespace eixx From 3ec814ea813d58535add0a0f78dc690807acf8d4 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 18 Feb 2016 23:23:29 -0500 Subject: [PATCH 094/185] Add list::to_pair() function --- include/eixx/marshal/list.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 9a5ba4a..850a389 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -42,10 +42,29 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace eixx { namespace marshal { + namespace { + } + template struct cons { eterm node; cons* next; + + // Try to decode the value as a pair containing atom + // option name and any value + bool to_pair(atom& a_opt, eterm& a_val) { + static const eterm s_pair = eterm::format("{A::atom(), V}"); + static const atom s_am_opt = atom("A"); + static const atom s_am_val = atom("V"); + + varbind binding; + if (s_pair.match(node, &binding)) { + a_opt = binding[s_am_opt]->to_atom(); + a_val = *binding[s_am_val]; + return true; + } + return false; + } }; template From 708555b66f00dd599844246ee11a653c3ff9acee Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 18 Feb 2016 23:37:21 -0500 Subject: [PATCH 095/185] Move list.to_pair() to eterm.to_pair() --- include/eixx/marshal/eterm.hpp | 15 ++++++++++++++- include/eixx/marshal/list.hpp | 19 ------------------- test/test_eterm.cpp | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 610bdaf..55012d5 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -220,7 +220,6 @@ class eterm { static void format(const Alloc& a_alloc, atom& m, atom& f, eterm& args, const char** fmt, va_list* pa) throw (err_format_exception); - public: eterm_type type() const { return m_type; } const char* type_string() const; @@ -433,6 +432,20 @@ class eterm { const trace& to_trace() const { check(TRACE); return vt.trc; } trace& to_trace() { check(TRACE); return vt.trc; } + // Try to decode the value as a pair containing atom + // option name and any value + bool to_pair(atom& a_opt, eterm& a_val) { + static const eterm s_pair = eterm::format("{A::atom(), V}"); + static const atom s_am_opt = atom("A"); + static const atom s_am_val = atom("V"); + + varbind binding; + if (!match(s_pair, &binding)) return false; + a_opt = binding[s_am_opt]->to_atom(); + a_val = *binding[s_am_val]; + return true; + } + // Checks if database of the term is of given type bool is_double() const { return m_type == DOUBLE; } diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 850a389..9a5ba4a 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -42,29 +42,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace eixx { namespace marshal { - namespace { - } - template struct cons { eterm node; cons* next; - - // Try to decode the value as a pair containing atom - // option name and any value - bool to_pair(atom& a_opt, eterm& a_val) { - static const eterm s_pair = eterm::format("{A::atom(), V}"); - static const atom s_am_opt = atom("A"); - static const atom s_am_val = atom("V"); - - varbind binding; - if (s_pair.match(node, &binding)) { - a_opt = binding[s_am_opt]->to_atom(); - a_val = *binding[s_am_val]; - return true; - } - return false; - } }; template diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 8babb44..460fd59 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -242,6 +242,24 @@ BOOST_AUTO_TEST_CASE( test_list4 ) l.push_back(eterm(atom("abc"))); l.close(); BOOST_REQUIRE_EQUAL(2u, l.length()); + + { + list l1{tuple{am_ok, 10}, tuple{am_error, "abc"}}; + + atom opt; + eterm val; + + for (auto& item : l1) { + BOOST_REQUIRE(item.to_pair(opt, val)); + if (opt == am_ok) + BOOST_REQUIRE_EQUAL(10, val.to_long()); + else if (opt == am_error) + BOOST_REQUIRE_EQUAL("abc", val.to_str()); + else + BOOST_REQUIRE(false); + } + + } } BOOST_AUTO_TEST_CASE( test_double ) From 2e9c09a4948797c6a92e14c32b1907bdebbee46c Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 17 Mar 2016 11:07:36 -0400 Subject: [PATCH 096/185] Remove dependency on BOOST branch_hints.hpp (issue #25) --- include/eixx/util/compiler_hints.hpp | 32 +++++++++++++++++++--------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/include/eixx/util/compiler_hints.hpp b/include/eixx/util/compiler_hints.hpp index 59a6abe..8fac97b 100644 --- a/include/eixx/util/compiler_hints.hpp +++ b/include/eixx/util/compiler_hints.hpp @@ -9,24 +9,36 @@ // Created: 2010-09-20 //---------------------------------------------------------------------------- -#ifndef _EIXX_COMPILER_HINTS_HPP_ -#define _EIXX_COMPILER_HINTS_HPP_ - -#include +#pragma once // Branch prediction optimization (see http://lwn.net/Articles/255364/) + +#ifndef NO_HINT_BRANCH_PREDICTION +# ifndef LIKELY +# define LIKELY(expr) __builtin_expect(!!(expr),1) +# endif +# ifndef UNLIKELY +# define UNLIKELY(expr) __builtin_expect(!!(expr),0) +# endif +#else +# ifndef LIKELY +# define LIKELY(expr) (expr) +# endif +# ifndef UNLIKELY +# define UNLIKELY(expr) (expr) +# endif +#endif + namespace eixx { +// Though the compiler should optimize this inlined code in the same way as +// when using LIKELY/UNLIKELY macros directly the preference is to use the later #ifndef NO_HINT_BRANCH_PREDICTION - inline bool likely(bool expr) { return boost::lockfree::detail::likely (expr); } - inline bool unlikely(bool expr) { return boost::lockfree::detail::unlikely(expr); } + inline bool likely(bool expr) { return __builtin_expect((expr),1); } + inline bool unlikely(bool expr) { return __builtin_expect((expr),0); } #else inline bool likely(bool expr) { return expr; } inline bool unlikely(bool expr) { return expr; } #endif - } // namespace eixx - -#endif // _EIXX_COMPILER_HINTS_HPP_ - From c664c900457ec5ec7cfd928d637d4eb9bc8ea219 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 17 Mar 2016 11:51:48 -0400 Subject: [PATCH 097/185] Consistency fix --- include/eixx/util/compiler_hints.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/eixx/util/compiler_hints.hpp b/include/eixx/util/compiler_hints.hpp index 8fac97b..a23e9d3 100644 --- a/include/eixx/util/compiler_hints.hpp +++ b/include/eixx/util/compiler_hints.hpp @@ -34,8 +34,8 @@ namespace eixx { // Though the compiler should optimize this inlined code in the same way as // when using LIKELY/UNLIKELY macros directly the preference is to use the later #ifndef NO_HINT_BRANCH_PREDICTION - inline bool likely(bool expr) { return __builtin_expect((expr),1); } - inline bool unlikely(bool expr) { return __builtin_expect((expr),0); } + inline bool likely(bool expr) { return __builtin_expect(!!(expr),1); } + inline bool unlikely(bool expr) { return __builtin_expect(!!(expr),0); } #else inline bool likely(bool expr) { return expr; } inline bool unlikely(bool expr) { return expr; } From 1d59aa5e76e138e9a491b510bf592a4c171248c4 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 14 Apr 2016 11:33:42 -0400 Subject: [PATCH 098/185] Add parsing of binary terms via eterm::format() --- include/eixx/marshal/eterm_format.hxx | 42 +++++++++++++++++++++++++++ include/eixx/util/string_util.hpp | 36 +++++++++++++++++++++-- test/test_eterm_format.cpp | 25 ++++++++++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/include/eixx/marshal/eterm_format.hxx b/include/eixx/marshal/eterm_format.hxx index 14eeb17..e1bfdb9 100644 --- a/include/eixx/marshal/eterm_format.hxx +++ b/include/eixx/marshal/eterm_format.hxx @@ -50,6 +50,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include #include #include //#include @@ -369,6 +370,47 @@ namespace marshal { ret = v.to_list(alloc); break; + case '<': { + if (**fmt != '<') + throw err_format_exception("Error parsing binary", *fmt); + bool str = *(*fmt + 1) == '"'; + if (str) { + *fmt += 2; + const char* end = strstr(*fmt, "\">>"); + if (!end) + throw err_format_exception("Cannot find end of binary", *fmt); + ret = eterm(binary(*fmt, end - *fmt, alloc)); + *fmt = end + 3; + } else { + const char* end = strstr(++(*fmt), ">>"); + if (!end) + throw err_format_exception("Cannot find end of binary", *fmt); + std::vector v; + auto p = *fmt; + + while (p < end) { + while (*p == ' ' || *p == '\t') ++p; + int byte; + auto q = fast_atoi(p, end, byte); + if (!q) + throw err_format_exception("Error parsing binary", p); + p = q; + if (byte < 0 || byte > 255) + throw err_format_exception("Invalid byte value in binary", p); + v.push_back((char)byte); + while (*p == ' ' || *p == '\t') ++p; + if (*p == ',') + ++p; + else if (p < end) + throw err_format_exception("Invalid byte delimiter in binary", p); + } + auto begin = &v[0]; + ret = eterm(binary(begin, v.size(), alloc)); + *fmt = end + 2; + } + break; + } + case '$': /* char-value? */ ret = eterm((int)(*(*fmt)++)); break; diff --git a/include/eixx/util/string_util.hpp b/include/eixx/util/string_util.hpp index 2c1a346..2166c98 100644 --- a/include/eixx/util/string_util.hpp +++ b/include/eixx/util/string_util.hpp @@ -43,7 +43,7 @@ namespace eixx { /// Print the content of a buffer to \a out stream in the form: /// \verbatim <> \endverbatim where Ik is /// unsigned integer less than 256. -static inline std::ostream& to_binary_string(std::ostream& out, const char* buf, size_t sz) { +inline std::ostream& to_binary_string(std::ostream& out, const char* buf, size_t sz) { out << "<<"; const char* begin = buf, *end = buf + sz; for(const char* p = begin; p != end; ++p) { @@ -56,12 +56,44 @@ static inline std::ostream& to_binary_string(std::ostream& out, const char* buf, /// Convert the content of a buffer to a binary string in the form: /// \verbatim <> \endverbatim where Ik is /// unsigned integer less than 256. -static inline std::string to_binary_string(const char* a, size_t sz) { +inline std::string to_binary_string(const char* a, size_t sz) { std::stringstream oss; to_binary_string(oss, a, sz); return oss.str(); } +/// Convert string to integer +/// +/// @tparam TillEOL instructs that the integer must be validated till a_end. +/// If false, "123ABC" is considered a valid 123 number. Otherwise +/// the function will return NULL. +/// @return input string ptr beyond the the value read if successful, NULL otherwise +// +template +inline const char* fast_atoi(const char* a_str, const char* a_end, T& res) { + if (a_str >= a_end) return nullptr; + + bool l_neg; + + if (*a_str == '-') { l_neg = true; ++a_str; } + else { l_neg = false; } + + T x = 0; + + do { + const int c = *a_str - '0'; + if (c < 0 || c > 9) { + if (TillEOL) + return nullptr; + break; + } + x = (x << 3) + (x << 1) + c; + } while (++a_str != a_end); + + res = l_neg ? -x : x; + return a_str; +} + } // namespace eixx namespace std { diff --git a/test/test_eterm_format.cpp b/test/test_eterm_format.cpp index 25db668..4d171bf 100644 --- a/test/test_eterm_format.cpp +++ b/test/test_eterm_format.cpp @@ -38,6 +38,31 @@ BOOST_AUTO_TEST_CASE( test_eterm_format_string ) BOOST_REQUIRE_EQUAL("abc", et.to_str()); } +BOOST_AUTO_TEST_CASE( test_eterm_format_binary ) +{ + allocator_t alloc; + + eterm et = eterm::format(alloc, "<<\"abc\">>"); + + BOOST_REQUIRE_EQUAL(BINARY, et.type()); + BOOST_REQUIRE_EQUAL("abc", std::string(et.to_binary().data(), et.to_binary().size())); + + et = eterm::format(alloc, "<<65,66, 67>>"); + BOOST_REQUIRE_EQUAL(BINARY, et.type()); + BOOST_REQUIRE_EQUAL("ABC", std::string(et.to_binary().data(), et.to_binary().size())); + + et = eterm::format(alloc, "<<>>"); + BOOST_REQUIRE_EQUAL(BINARY, et.type()); + BOOST_REQUIRE_EQUAL("", std::string(et.to_binary().data(), et.to_binary().size())); + + et = eterm::format(alloc, "<<\"\">>"); + BOOST_REQUIRE_EQUAL(BINARY, et.type()); + BOOST_REQUIRE_EQUAL("", std::string(et.to_binary().data(), et.to_binary().size())); + + BOOST_CHECK_THROW(eterm::format("<<-1>>"), err_format_exception); + BOOST_CHECK_THROW(eterm::format("<<1,2 3>>"), err_format_exception); +} + BOOST_AUTO_TEST_CASE( test_eterm_format_atom ) { allocator_t alloc; From 3816115ea7c58521e0462d13530bb23239039ac3 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 14 Apr 2016 11:40:01 -0400 Subject: [PATCH 099/185] Remove release warning --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0acb7c2..b131f2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/build-aux/CMakeEx.txt) if("${toolchain}" STREQUAL "gcc") set(CMAKE_C_COMPILER "gcc") set(CMAKE_CXX_COMPILER "g++") - add_definitions(-Wno-strict-aliasing -fopenmp -Wall) + add_definitions(-fopenmp -Wall -Wno-strict-aliasing) if("${CMAKE_BUILD_TYPE}" STREQUAL "release") add_definitions(-flto -funroll-loops -fomit-frame-pointer) @@ -44,7 +44,7 @@ elseif("${toolchain}" STREQUAL "intel") elseif("${toolchain}" STREQUAL "clang") set(CMAKE_C_COMPILER "clang") set(CMAKE_CXX_COMPILER "clang++") - add_definitions(-Wall) + add_definitions(-Wall -Wno-strict-aliasing) else() message(FATAL_ERROR "Invalid toolchain: ${TOOLCHAIN}") endif() From a9790a84927590d1981cceab2dc74a59d8d39288 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 14 Apr 2016 11:56:11 -0400 Subject: [PATCH 100/185] Fix prefix argument to make --- bootstrap.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap.mk b/bootstrap.mk index da80f4c..c25dd06 100644 --- a/bootstrap.mk +++ b/bootstrap.mk @@ -71,7 +71,7 @@ ROOT_DIR := $(dir $(abspath include)) DEF_BLD_DIR := $(ROOT_DIR:%/=%)/build DIR := $(if $(BLD_DIR),$(BLD_DIR),$(DEF_BLD_DIR)) PREFIX := $(call substitute,DIR:INSTALL,$(OPT_FILE)) -prefix := $(if $(PREFIX),$(PREFIX),/usr/local) +prefix ?= $(if $(PREFIX),$(PREFIX),/usr/local) generator ?= make #------------------------------------------------------------------------------- @@ -88,7 +88,7 @@ info: @echo "prefix: $(prefix)" @echo "generator: $(generator)" -variables := $(filter-out toolchain=% generator=% build=% verbose=%,$(MAKEOVERRIDES)) +variables := $(filter-out toolchain=% generator=% build=% verbose=% prefix=%,$(MAKEOVERRIDES)) makevars := $(variables:%=-D%) envvars += $(shell sed -n '/^ENV:/{s/^ENV://;p}' $(OPT_FILE) 2>/dev/null) From fdfd99c30965eb2bc4d9cf3e3b1f735b0a9445e2 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 14 Apr 2016 12:04:15 -0400 Subject: [PATCH 101/185] Add make ver target --- Makefile | 2 +- bootstrap.mk | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b7fc217..370e4f3 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ rebootstrap: .build/.bootstrap test: CTEST_OUTPUT_ON_FAILURE=TRUE $(generator) -C$(DIR) $(VERBOSE) -j$(shell nproc) $@ -info: +info ver: @$(MAKE) -sf bootstrap.mk --no-print-directory $@ vars: diff --git a/bootstrap.mk b/bootstrap.mk index c25dd06..b2aa5a4 100644 --- a/bootstrap.mk +++ b/bootstrap.mk @@ -88,6 +88,9 @@ info: @echo "prefix: $(prefix)" @echo "generator: $(generator)" +ver: + @echo $(VERSION) + variables := $(filter-out toolchain=% generator=% build=% verbose=% prefix=%,$(MAKEOVERRIDES)) makevars := $(variables:%=-D%) From 8a15e2b7eb01c590613c950396126c74899e1b3c Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 10 May 2016 01:35:21 -0400 Subject: [PATCH 102/185] Split library installation into a separate clause --- Makefile | 2 +- src/CMakeLists.txt | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 370e4f3..e2d1f61 100644 --- a/Makefile +++ b/Makefile @@ -52,4 +52,4 @@ build/cache.mk: -j$(shell nproc) $@;\ fi -.PHONY: bootstrap rebootstrap distclean info test +.PHONY: bootstrap rebootstrap distclean info test doc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b9b3eb4..2eb2fb2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,10 @@ add_executable(test-node test_node.cpp) target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) target_link_libraries(test-node eixx pthread) +# In the install below we split library installation in a separate library clause +# so that it's possible to build/install both Release and Debug versions of the +# library and then include that into a package + install( TARGETS ${PROJECT_NAME} @@ -33,6 +37,13 @@ install( LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) + +install( + DIRECTORY ${CMAKE_BINARY_DIR}/src/ + DESTINATION lib + FILES_MATCHING PATTERN "libeixx*.so*" PATTERN "libeixx*.a*" +) + install( TARGETS test-node From c0ca504ceb9a2b4e836b2ad1d483e067f793b8b2 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 10 May 2016 01:41:25 -0400 Subject: [PATCH 103/185] Split library installation into a separate clause --- src/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2eb2fb2..676192e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,7 +41,9 @@ install( install( DIRECTORY ${CMAKE_BINARY_DIR}/src/ DESTINATION lib - FILES_MATCHING PATTERN "libeixx*.so*" PATTERN "libeixx*.a*" + FILES_MATCHING + PATTERN "${CMAKE_BINARY_DIR}/src/libeixx*.so*" + PATTERN "${CMAKE_BINARY_DIR}/src/libeixx*.a*" ) install( From af6b760126feaafc1a6dbca07ba656b9dfc06cd3 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 10 May 2016 01:48:09 -0400 Subject: [PATCH 104/185] Split library installation into a separate clause --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 676192e..4cdf2d7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,6 +44,7 @@ install( FILES_MATCHING PATTERN "${CMAKE_BINARY_DIR}/src/libeixx*.so*" PATTERN "${CMAKE_BINARY_DIR}/src/libeixx*.a*" + PATTERN "CMakeFiles/" EXCLUDE ) install( From 27da34d1c300bd13664758e999198f795fe511cb Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 10 May 2016 01:49:42 -0400 Subject: [PATCH 105/185] Split library installation into a separate clause --- src/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4cdf2d7..db73c29 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,8 +42,8 @@ install( DIRECTORY ${CMAKE_BINARY_DIR}/src/ DESTINATION lib FILES_MATCHING - PATTERN "${CMAKE_BINARY_DIR}/src/libeixx*.so*" - PATTERN "${CMAKE_BINARY_DIR}/src/libeixx*.a*" + PATTERN "libeixx*.so*" + PATTERN "libeixx*.a*" PATTERN "CMakeFiles/" EXCLUDE ) From 5e1542db290a2f600168483a2745d958e4cce9c0 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 10 May 2016 01:57:43 -0400 Subject: [PATCH 106/185] Split library installation into a separate clause --- src/CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db73c29..11a07b5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -38,14 +38,14 @@ install( ARCHIVE DESTINATION lib ) -install( - DIRECTORY ${CMAKE_BINARY_DIR}/src/ - DESTINATION lib - FILES_MATCHING - PATTERN "libeixx*.so*" - PATTERN "libeixx*.a*" - PATTERN "CMakeFiles/" EXCLUDE -) +if (${CMAKE_BUILD_TYPE} STREQUAL "release") + install( + FILES ${CMAKE_BINARY_DIR}/src/lib${PROJECT_NAME}${LIB_SUFFIX}.so.${PROJECT_VERSION} + FILES ${CMAKE_BINARY_DIR}/src/lib${PROJECT_NAME}${LIB_SUFFIX}.so + FILES ${CMAKE_BINARY_DIR}/src/lib${PROJECT_NAME}${LIB_SUFFIX}.a + DESTINATION lib + ) +endif() install( TARGETS From 6d8d5068f0217c6ca90cbf6980c1ee523262c67b Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 10 May 2016 02:01:19 -0400 Subject: [PATCH 107/185] Split library installation into a separate clause --- src/CMakeLists.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 11a07b5..884e5c1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,9 +40,15 @@ install( if (${CMAKE_BUILD_TYPE} STREQUAL "release") install( - FILES ${CMAKE_BINARY_DIR}/src/lib${PROJECT_NAME}${LIB_SUFFIX}.so.${PROJECT_VERSION} - FILES ${CMAKE_BINARY_DIR}/src/lib${PROJECT_NAME}${LIB_SUFFIX}.so - FILES ${CMAKE_BINARY_DIR}/src/lib${PROJECT_NAME}${LIB_SUFFIX}.a + FILES ${CMAKE_BINARY_DIR}/src/lib${PROJECT_NAME}_d.so.${PROJECT_VERSION} + DESTINATION lib + ) + install( + FILES ${CMAKE_BINARY_DIR}/src/lib${PROJECT_NAME}_d.so + DESTINATION lib + ) + install( + FILES ${CMAKE_BINARY_DIR}/src/lib${PROJECT_NAME}_a.so DESTINATION lib ) endif() From cd24f3d9a1090f33cfc516b4528b54c12f552c09 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 10 May 2016 02:02:53 -0400 Subject: [PATCH 108/185] Split library installation into a separate clause --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 884e5c1..f89f7b9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,7 +48,7 @@ if (${CMAKE_BUILD_TYPE} STREQUAL "release") DESTINATION lib ) install( - FILES ${CMAKE_BINARY_DIR}/src/lib${PROJECT_NAME}_a.so + FILES ${CMAKE_BINARY_DIR}/src/lib${PROJECT_NAME}_d.a DESTINATION lib ) endif() From a846e99eb73a951817bf68af6f74b09936a3cfc4 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Fri, 13 May 2016 14:51:59 -0400 Subject: [PATCH 109/185] Update README --- README.md | 12 +++++++++++- eixx.pc.in | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d48875c..07abcdc 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,16 @@ $ make bootstrap [toolchain=gcc|clang] [build=Debug|Release] \ $ make [verbose=true] $ make install # Default install path is /usr/local ``` +There is a slight difference between installing release and debug builds. The release +build installer also tries to install a "debug version" of eixx (`libeixx_d.so`) that +must be build using build type `"debug"`. So for a release build do: +``` +$ make bootstrap build=debug +$ make src/libeixx_d.so +$ make rebootstrap build=release +$ make +$ make install +``` After running `make bootstrap` two local links are created `build` and `inst` pointing to build and installation directories. @@ -283,4 +293,4 @@ registered on the C++ node: #DistMsg{ type=REG_SEND, cntrl={6,#Pid,'',main}, - msg="This is a test!"} \ No newline at end of file + msg="This is a test!"} diff --git a/eixx.pc.in b/eixx.pc.in index 83eb385..3346882 100644 --- a/eixx.pc.in +++ b/eixx.pc.in @@ -1,12 +1,13 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=@CMAKE_INSTALL_PREFIX@/lib +libsuffix=@LIB_SUFFIX@ includedir=@CMAKE_INSTALL_PREFIX@/include Name: @PROJECT_NAME@ Description: EIXX: C++ Interface to Erlang #Requires: boost_1_55_0 Version: @PROJECT_VERSION@ -Libs: -L${libdir} -L@Erlang_EI_LIBRARY_PATH@ -Wl,-rpath,${libdir} -leixx -lei -lssl -lcrypto +Libs: -L${libdir} -L@Erlang_EI_LIBRARY_PATH@ -Wl,-rpath,${libdir} -leixx${libsuffix} -lei -lssl -lcrypto Cflags: -I${includedir} -I@Erlang_EI_INCLUDE_DIR@ From 050b01a32906e0868794b00d9be19a853f094d1e Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 21 Aug 2016 11:28:24 -0400 Subject: [PATCH 110/185] Fix embedded license clauses to be consistent with LICENSE file --- include/eixx/alloc_pool.hpp | 24 ++++++------- include/eixx/alloc_pool_st.hpp | 24 ++++++------- include/eixx/alloc_std.hpp | 24 ++++++------- include/eixx/alloc_std_debug.hpp | 24 ++++++------- include/eixx/connect.hpp | 24 ++++++------- include/eixx/connect/basic_otp_connection.hpp | 24 ++++++------- include/eixx/connect/basic_otp_mailbox.hpp | 24 ++++++------- include/eixx/connect/basic_otp_mailbox.hxx | 24 ++++++------- .../connect/basic_otp_mailbox_registry.hpp | 24 ++++++------- .../connect/basic_otp_mailbox_registry.hxx | 24 ++++++------- include/eixx/connect/basic_otp_node.hpp | 24 ++++++------- include/eixx/connect/basic_otp_node.hxx | 24 ++++++------- include/eixx/connect/basic_otp_node_local.hpp | 24 ++++++------- .../eixx/connect/detail/basic_rpc_server.hpp | 24 ++++++------- include/eixx/connect/transport_msg.hpp | 24 ++++++------- .../eixx/connect/transport_otp_connection.hpp | 34 ++++++++----------- .../eixx/connect/transport_otp_connection.hxx | 24 ++++++------- .../connect/transport_otp_connection_tcp.hpp | 24 ++++++------- .../connect/transport_otp_connection_tcp.hxx | 24 ++++++------- .../connect/transport_otp_connection_uds.hpp | 24 ++++++------- include/eixx/eixx.hpp | 24 ++++++------- include/eixx/eterm.hpp | 24 ++++++------- include/eixx/eterm_exception.hpp | 24 ++++++------- include/eixx/marshal/alloc_base.hpp | 24 ++++++------- include/eixx/marshal/am.hpp | 24 ++++++------- include/eixx/marshal/atom.hpp | 24 ++++++------- include/eixx/marshal/binary.hpp | 24 ++++++------- include/eixx/marshal/binary.hxx | 24 ++++++------- include/eixx/marshal/defaults.hpp | 24 ++++++------- .../marshal/detail/array_variadic_init.hpp | 24 ++++++------- include/eixx/marshal/endian.hpp | 22 ++++++------ include/eixx/marshal/eterm.hpp | 24 ++++++------- include/eixx/marshal/eterm.hxx | 24 ++++++------- include/eixx/marshal/eterm_format.hpp | 22 ++++++------ include/eixx/marshal/eterm_format.hxx | 24 ++++++------- include/eixx/marshal/eterm_match.hpp | 25 ++++++-------- include/eixx/marshal/list.hpp | 24 ++++++------- include/eixx/marshal/list.hxx | 26 ++++++-------- include/eixx/marshal/pid.hpp | 24 ++++++------- include/eixx/marshal/pid.hxx | 24 ++++++------- include/eixx/marshal/port.hpp | 24 ++++++------- include/eixx/marshal/port.hxx | 24 ++++++------- include/eixx/marshal/ref.hpp | 24 ++++++------- include/eixx/marshal/ref.hxx | 24 ++++++------- include/eixx/marshal/string.hpp | 24 ++++++------- include/eixx/marshal/trace.hpp | 24 ++++++------- include/eixx/marshal/tuple.hpp | 24 ++++++------- include/eixx/marshal/tuple.hxx | 24 ++++++------- include/eixx/marshal/var.hpp | 24 ++++++------- include/eixx/marshal/varbind.hpp | 24 ++++++------- include/eixx/marshal/visit.hpp | 24 ++++++------- include/eixx/marshal/visit_encode_size.hpp | 24 ++++++------- include/eixx/marshal/visit_encoder.hpp | 24 ++++++------- include/eixx/marshal/visit_match.hpp | 24 ++++++------- include/eixx/marshal/visit_subst.hpp | 24 ++++++------- include/eixx/marshal/visit_to_string.hpp | 24 ++++++------- include/eixx/util/async_queue.hpp | 24 ++++++------- include/eixx/util/atom_table.hpp | 24 ++++++------- include/eixx/util/hashtable.hpp | 24 ++++++------- include/eixx/util/string_util.hpp | 24 ++++++------- include/eixx/util/sync.hpp | 24 ++++++------- src/am.cpp | 24 ++++++------- src/basic_otp_node_local.cpp | 24 ++++++------- test/test_async_queue.cpp | 24 ++++++------- test/test_eterm.cpp | 24 ++++++------- test/test_eterm_encode.cpp | 24 ++++++------- test/test_eterm_format.cpp | 26 ++++++-------- test/test_eterm_match.cpp | 24 ++++++------- test/test_eterm_pool.cpp | 24 ++++++------- test/test_eterm_refc.cpp | 26 ++++++-------- test/test_mailbox.cpp | 24 ++++++------- test/test_node.cpp | 24 ++++++------- 72 files changed, 728 insertions(+), 1013 deletions(-) diff --git a/include/eixx/alloc_pool.hpp b/include/eixx/alloc_pool.hpp index cfb7a02..9eddd40 100644 --- a/include/eixx/alloc_pool.hpp +++ b/include/eixx/alloc_pool.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/alloc_pool_st.hpp b/include/eixx/alloc_pool_st.hpp index f492039..4b75c12 100644 --- a/include/eixx/alloc_pool_st.hpp +++ b/include/eixx/alloc_pool_st.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/alloc_std.hpp b/include/eixx/alloc_std.hpp index b412022..a000e3c 100644 --- a/include/eixx/alloc_std.hpp +++ b/include/eixx/alloc_std.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/alloc_std_debug.hpp b/include/eixx/alloc_std_debug.hpp index 4103274..fe781e0 100644 --- a/include/eixx/alloc_std_debug.hpp +++ b/include/eixx/alloc_std_debug.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect.hpp b/include/eixx/connect.hpp index 49f8f11..b50edd1 100644 --- a/include/eixx/connect.hpp +++ b/include/eixx/connect.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/basic_otp_connection.hpp b/include/eixx/connect/basic_otp_connection.hpp index 89fc2d2..2d74539 100644 --- a/include/eixx/connect/basic_otp_connection.hpp +++ b/include/eixx/connect/basic_otp_connection.hpp @@ -11,23 +11,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index 4fdca4d..c052ba6 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -11,23 +11,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/basic_otp_mailbox.hxx b/include/eixx/connect/basic_otp_mailbox.hxx index 1c5fcd4..8dfa6fe 100644 --- a/include/eixx/connect/basic_otp_mailbox.hxx +++ b/include/eixx/connect/basic_otp_mailbox.hxx @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/basic_otp_mailbox_registry.hpp b/include/eixx/connect/basic_otp_mailbox_registry.hpp index 2ed5399..7a3e756 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.hpp +++ b/include/eixx/connect/basic_otp_mailbox_registry.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/basic_otp_mailbox_registry.hxx b/include/eixx/connect/basic_otp_mailbox_registry.hxx index 5d8375a..14d8017 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.hxx +++ b/include/eixx/connect/basic_otp_mailbox_registry.hxx @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index 993b97d..c49b98b 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -13,23 +13,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/basic_otp_node.hxx b/include/eixx/connect/basic_otp_node.hxx index 7673095..87a2368 100644 --- a/include/eixx/connect/basic_otp_node.hxx +++ b/include/eixx/connect/basic_otp_node.hxx @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/basic_otp_node_local.hpp b/include/eixx/connect/basic_otp_node_local.hpp index c26c31a..e68be37 100644 --- a/include/eixx/connect/basic_otp_node_local.hpp +++ b/include/eixx/connect/basic_otp_node_local.hpp @@ -12,23 +12,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/detail/basic_rpc_server.hpp b/include/eixx/connect/detail/basic_rpc_server.hpp index 618773c..cf663d0 100644 --- a/include/eixx/connect/detail/basic_rpc_server.hpp +++ b/include/eixx/connect/detail/basic_rpc_server.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2013 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/transport_msg.hpp b/include/eixx/connect/transport_msg.hpp index c387e37..cb6eb08 100644 --- a/include/eixx/connect/transport_msg.hpp +++ b/include/eixx/connect/transport_msg.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index dcb06e6..7ea9b43 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -8,25 +8,21 @@ //---------------------------------------------------------------------------- /* * ***** BEGIN LICENSE BLOCK ***** - * - * This file is part of the eixx (Erlang C++ Interface) library. - * - * Copyright (c) 2010 Serge Aleynikov - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + +Copyright 2010 Serge Aleynikov + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +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. + * ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/transport_otp_connection.hxx b/include/eixx/connect/transport_otp_connection.hxx index 1607c31..cf81e5a 100644 --- a/include/eixx/connect/transport_otp_connection.hxx +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -7,23 +7,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 98d83c5..2c4896f 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index c1c0afe..1dd936d 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/connect/transport_otp_connection_uds.hpp b/include/eixx/connect/transport_otp_connection_uds.hpp index ae843ab..8205d7b 100644 --- a/include/eixx/connect/transport_otp_connection_uds.hpp +++ b/include/eixx/connect/transport_otp_connection_uds.hpp @@ -12,23 +12,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/eixx.hpp b/include/eixx/eixx.hpp index 4b8c64f..54bf6d5 100644 --- a/include/eixx/eixx.hpp +++ b/include/eixx/eixx.hpp @@ -14,23 +14,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index 35008ee..2f57156 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/eterm_exception.hpp b/include/eixx/eterm_exception.hpp index a599ab2..286c344 100644 --- a/include/eixx/eterm_exception.hpp +++ b/include/eixx/eterm_exception.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (c) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/alloc_base.hpp b/include/eixx/marshal/alloc_base.hpp index 65f4ad2..41b99d5 100644 --- a/include/eixx/marshal/alloc_base.hpp +++ b/include/eixx/marshal/alloc_base.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/am.hpp b/include/eixx/marshal/am.hpp index f8698ff..91a5d40 100644 --- a/include/eixx/marshal/am.hpp +++ b/include/eixx/marshal/am.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index ec23af8..29bb664 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/binary.hpp b/include/eixx/marshal/binary.hpp index ebeb0d7..beafdc6 100644 --- a/include/eixx/marshal/binary.hpp +++ b/include/eixx/marshal/binary.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/binary.hxx b/include/eixx/marshal/binary.hxx index 65480bc..cfcc31e 100644 --- a/include/eixx/marshal/binary.hxx +++ b/include/eixx/marshal/binary.hxx @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/defaults.hpp b/include/eixx/marshal/defaults.hpp index 812bce6..6d110dd 100644 --- a/include/eixx/marshal/defaults.hpp +++ b/include/eixx/marshal/defaults.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/detail/array_variadic_init.hpp b/include/eixx/marshal/detail/array_variadic_init.hpp index e24a058..9e09e57 100644 --- a/include/eixx/marshal/detail/array_variadic_init.hpp +++ b/include/eixx/marshal/detail/array_variadic_init.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2013 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/endian.hpp b/include/eixx/marshal/endian.hpp index 4d370d7..a5bc394 100644 --- a/include/eixx/marshal/endian.hpp +++ b/include/eixx/marshal/endian.hpp @@ -9,21 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -Copyright (C) 2010 Serge Aleynikov +Copyright 2010 Serge Aleynikov -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. + http://www.apache.org/licenses/LICENSE-2.0 -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 55012d5..642e186 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index 4101f9c..993f8c8 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/eterm_format.hpp b/include/eixx/marshal/eterm_format.hpp index 3ec3c4a..209f855 100644 --- a/include/eixx/marshal/eterm_format.hpp +++ b/include/eixx/marshal/eterm_format.hpp @@ -9,21 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -Copyright (C) 2010 Serge Aleynikov +Copyright 2010 Serge Aleynikov -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. + http://www.apache.org/licenses/LICENSE-2.0 -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/eterm_format.hxx b/include/eixx/marshal/eterm_format.hxx index e1bfdb9..8ef7e8b 100644 --- a/include/eixx/marshal/eterm_format.hxx +++ b/include/eixx/marshal/eterm_format.hxx @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index c8f12cb..e7f326f 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -12,24 +12,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov -Copyright (C) 2005 Hector Rivas Gandara +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 9a5ba4a..0c471c9 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/list.hxx b/include/eixx/marshal/list.hxx index 3f2f8fa..4157b7c 100644 --- a/include/eixx/marshal/list.hxx +++ b/include/eixx/marshal/list.hxx @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ @@ -287,4 +283,4 @@ std::ostream& list::dump(std::ostream& out, const varbind* vars) c } } // namespace marshal -} // namespace eixx \ No newline at end of file +} // namespace eixx diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index 1c154a8..3a0b4ef 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/pid.hxx b/include/eixx/marshal/pid.hxx index 70e7349..db77c76 100644 --- a/include/eixx/marshal/pid.hxx +++ b/include/eixx/marshal/pid.hxx @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index e65573f..8660bd0 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index c73e484..a14e6c3 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index 41502aa..cfa0e5a 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/ref.hxx b/include/eixx/marshal/ref.hxx index 13f2352..6bc8321 100644 --- a/include/eixx/marshal/ref.hxx +++ b/include/eixx/marshal/ref.hxx @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index 5c64bf1..7eeb84a 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/trace.hpp b/include/eixx/marshal/trace.hpp index 6c9c499..3a3a6f2 100644 --- a/include/eixx/marshal/trace.hpp +++ b/include/eixx/marshal/trace.hpp @@ -12,23 +12,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/tuple.hpp b/include/eixx/marshal/tuple.hpp index 40f6e68..a139b5f 100644 --- a/include/eixx/marshal/tuple.hpp +++ b/include/eixx/marshal/tuple.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/tuple.hxx b/include/eixx/marshal/tuple.hxx index c781888..8ac0047 100644 --- a/include/eixx/marshal/tuple.hxx +++ b/include/eixx/marshal/tuple.hxx @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/var.hpp b/include/eixx/marshal/var.hpp index 1f12a4c..0d0fc2b 100644 --- a/include/eixx/marshal/var.hpp +++ b/include/eixx/marshal/var.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/varbind.hpp b/include/eixx/marshal/varbind.hpp index d783135..55561fd 100644 --- a/include/eixx/marshal/varbind.hpp +++ b/include/eixx/marshal/varbind.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/visit.hpp b/include/eixx/marshal/visit.hpp index e370b2a..2febad3 100644 --- a/include/eixx/marshal/visit.hpp +++ b/include/eixx/marshal/visit.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/visit_encode_size.hpp b/include/eixx/marshal/visit_encode_size.hpp index 39ae677..2f139d9 100644 --- a/include/eixx/marshal/visit_encode_size.hpp +++ b/include/eixx/marshal/visit_encode_size.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/visit_encoder.hpp b/include/eixx/marshal/visit_encoder.hpp index 9adf09b..04b65a5 100644 --- a/include/eixx/marshal/visit_encoder.hpp +++ b/include/eixx/marshal/visit_encoder.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/visit_match.hpp b/include/eixx/marshal/visit_match.hpp index 5e40752..9bb3e66 100644 --- a/include/eixx/marshal/visit_match.hpp +++ b/include/eixx/marshal/visit_match.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/visit_subst.hpp b/include/eixx/marshal/visit_subst.hpp index 2d69e26..c263cb9 100644 --- a/include/eixx/marshal/visit_subst.hpp +++ b/include/eixx/marshal/visit_subst.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/marshal/visit_to_string.hpp b/include/eixx/marshal/visit_to_string.hpp index 539eec9..36995d6 100644 --- a/include/eixx/marshal/visit_to_string.hpp +++ b/include/eixx/marshal/visit_to_string.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index 5c52264..63fab93 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx open-source project. +Copyright 2010 Serge Aleynikov -Copyright (C) 2013 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 6bb0bec..1020eb2 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/util/hashtable.hpp b/include/eixx/util/hashtable.hpp index 0895662..2ccdf7a 100644 --- a/include/eixx/util/hashtable.hpp +++ b/include/eixx/util/hashtable.hpp @@ -1,23 +1,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/util/string_util.hpp b/include/eixx/util/string_util.hpp index 2166c98..109666a 100644 --- a/include/eixx/util/string_util.hpp +++ b/include/eixx/util/string_util.hpp @@ -10,23 +10,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/include/eixx/util/sync.hpp b/include/eixx/util/sync.hpp index 3be5c0a..bcbd260 100644 --- a/include/eixx/util/sync.hpp +++ b/include/eixx/util/sync.hpp @@ -1,23 +1,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/src/am.cpp b/src/am.cpp index a9d8043..a7fb48f 100644 --- a/src/am.cpp +++ b/src/am.cpp @@ -1,23 +1,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/src/basic_otp_node_local.cpp b/src/basic_otp_node_local.cpp index ae74ea1..0378f2f 100644 --- a/src/basic_otp_node_local.cpp +++ b/src/basic_otp_node_local.cpp @@ -1,23 +1,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the eixx (Erlang C++ Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/test/test_async_queue.cpp b/test/test_async_queue.cpp index d148f59..fc3ca21 100644 --- a/test/test_async_queue.cpp +++ b/test/test_async_queue.cpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 460fd59..35ecab2 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -1,23 +1,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/test/test_eterm_encode.cpp b/test/test_eterm_encode.cpp index 5ce0aff..6a201d5 100644 --- a/test/test_eterm_encode.cpp +++ b/test/test_eterm_encode.cpp @@ -1,23 +1,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/test/test_eterm_format.cpp b/test/test_eterm_format.cpp index 4d171bf..6207ade 100644 --- a/test/test_eterm_format.cpp +++ b/test/test_eterm_format.cpp @@ -1,23 +1,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ @@ -212,4 +208,4 @@ BOOST_AUTO_TEST_CASE( test_eterm_mfa_format_bad ) BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a:b(10.(20)"), err_format_exception); BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a:b(~i,~i]", 10, 20), err_format_exception); BOOST_REQUIRE_THROW(eterm::format(m, f, args, "a:b([[~i,20],]", 10), err_format_exception); -} \ No newline at end of file +} diff --git a/test/test_eterm_match.cpp b/test/test_eterm_match.cpp index e6c25a0..99db984 100644 --- a/test/test_eterm_match.cpp +++ b/test/test_eterm_match.cpp @@ -1,23 +1,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/test/test_eterm_pool.cpp b/test/test_eterm_pool.cpp index 1a8ac21..5095f98 100644 --- a/test/test_eterm_pool.cpp +++ b/test/test_eterm_pool.cpp @@ -1,23 +1,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/test/test_eterm_refc.cpp b/test/test_eterm_refc.cpp index b58d606..37b606f 100644 --- a/test/test_eterm_refc.cpp +++ b/test/test_eterm_refc.cpp @@ -1,23 +1,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ @@ -137,4 +133,4 @@ BOOST_AUTO_TEST_CASE( test_refc_list ) BOOST_CHECK_EQUAL(2, g_alloc_count); } BOOST_CHECK_EQUAL(2, g_alloc_count); -} \ No newline at end of file +} diff --git a/test/test_mailbox.cpp b/test/test_mailbox.cpp index fe1dba7..aadc6f7 100644 --- a/test/test_mailbox.cpp +++ b/test/test_mailbox.cpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ diff --git a/test/test_node.cpp b/test/test_node.cpp index d84d511..a02acc4 100644 --- a/test/test_node.cpp +++ b/test/test_node.cpp @@ -9,23 +9,19 @@ /* ***** BEGIN LICENSE BLOCK ***** -This file is part of the EPI (Erlang Plus Interface) Library. +Copyright 2010 Serge Aleynikov -Copyright (C) 2010 Serge Aleynikov +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +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. ***** END LICENSE BLOCK ***** */ From 146a274b4b10204d5db3bc9fe966528c064347e4 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 21 Aug 2016 11:32:23 -0400 Subject: [PATCH 111/185] Update README --- README.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 07abcdc..895219b 100644 --- a/README.md +++ b/README.md @@ -6,22 +6,19 @@ distributed Erlang nodes from a C++ application. The marshaling classes are built on top of ei library included in http://www.erlang.org/doc/apps/erl_interface. -It is largely inspired by the http://code.google.com/p/epi -project, but is a complete rewrite with many new features and -optimization enhancements. - -This library adds on the following features: - - Use of reference-counted smart pointers for complex terms and - by-value copied simple terms (e.i. integers, doubles, bool, atoms). - - Ability to provide custom memory allocators. - - Encoding/decoding of nested terms using a single function call - (eterm::encode() and eterm::eterm() constructor). - - Global atom table for fast manipulation of atoms. The library consists of two separate parts: - Term marshaling (included by eterm.hpp or eixx.hpp). - Distributed node connectivity (included by connect.hpp or eixx.hpp) +The term marshaling part of the library has following features: + - Encoding/decoding of nested terms using a single function call + (eterm::encode() and eterm::eterm() constructor). + - Global atom table for fast manipulation of atoms. + - Ability to provide custom memory allocators. + - Use of reference-counted smart pointers for complex terms and + by-value copied simple terms (e.i. integers, doubles, bool, atoms). + If you are simply doing term marshalling only the eterm.hpp header along with one of the alloc headers is needed. This allows for header-only usage of the marshalling capabilities. From 732a2baaab36fa7db5159c18f30683ae5103bc7b Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 21 Aug 2016 11:34:16 -0400 Subject: [PATCH 112/185] Fix Travis build --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e8c5121..b796ad7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,8 @@ addons: - gcc-4.9 - g++-4.9 - libboost1.55-all-dev + - cmake + - cmake-data - libxslt1.1 - python-lxml - graphviz @@ -26,7 +28,6 @@ before_install: - sudo add-apt-repository -y "deb http://ppa.launchpad.net/kzemek/boost/ubuntu utopic main" - sudo add-apt-repository ppa:george-edison55/precise-backports --yes - sudo apt-get update -qq - - sudo apt-get install cmake-data cmake - # sudo apt-get install libboost1.55-all-dev - # sudo updatedb - # dpkg -S /usr/include/boost/version.hpp From fdd3e88c4ead94cf7c472cbb90e8637c9b3f08d1 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 21 Aug 2016 12:23:55 -0400 Subject: [PATCH 113/185] Add NOTICES file --- NOTICES | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 NOTICES diff --git a/NOTICES b/NOTICES new file mode 100644 index 0000000..60a62e1 --- /dev/null +++ b/NOTICES @@ -0,0 +1,5 @@ +Erlang Interface C++ (eixx) +Copyright (c) 2010-2016 Serge Aleynikov + +The eixx project is developed by Serge Aleynikov . +It's source code is hosted at: https://github.com/saleyn/eixx. From 232f3f202403969ce591e5f377f58088ddddafe6 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 21 Aug 2016 12:34:10 -0400 Subject: [PATCH 114/185] Fix Travis cmake --- .travis.yml | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b796ad7..8474712 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,19 +35,35 @@ before_install: - # find /usr/include/boost -print | head -100 - # grep BOOST_LIB_VERSION /usr/include/boost/version.hpp | grep define - # locate libboost | head -100 - - sudo apt-get install -qq libthrift-dev libthrift0 thrift-compiler + - # sudo apt-get install -qq libthrift-dev libthrift0 thrift-compiler - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 90 before_script: - echo "DIR:BUILD=/tmp/${USER}/utxx" > .cmake-args.$(hostname) - echo "DIR:INSTALL=/tmp/${USER}/install/@PROJECT@/@VERSION@" >> .cmake-args.$(hostname) - echo "PKG_ROOT_DIR=/usr/local" >> .cmake-args.$(hostname) - - echo "WITH_THRIFT=OFF" >> .cmake-args.$(hostname) - echo "BOOST_INCLUDEDIR=/usr/include" >> .cmake-args.$(hostname) - echo "BOOST_LIBRARYDIR=/usr/lib/x86_64-linux-gnu" >> .cmake-args.$(hostname) - - echo "WITH_ENUM_SERIALIZATION=ON" >> .cmake-args.$(hostname) - g++ --version script: + ############################################################################ + # All the dependencies are installed in ${TRAVIS_BUILD_DIR}/deps/ + ############################################################################ + - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" + - mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR} + + ############################################################################ + # Install a recent CMake (unless already installed on OS X) + ############################################################################ + - | + if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then + CMAKE_URL="http://www.cmake.org/files/v3.5/cmake-3.5.2-Linux-x86_64.tar.gz" + mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake + export PATH=${DEPS_DIR}/cmake/bin:${PATH} + else + if ! brew ls --version cmake &>/dev/null; then brew install cmake; fi + fi + - make bootstrap generator=make build=Debug - make - make doc > build/doc.log From c4fe8dd06d1f25302532a69ba6e30a7251110776 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sun, 21 Aug 2016 12:38:45 -0400 Subject: [PATCH 115/185] Fix Travis cmake --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 8474712..fb52185 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,6 +64,7 @@ script: if ! brew ls --version cmake &>/dev/null; then brew install cmake; fi fi + - cd ${TRAVIS_BUILD_DIR} # Go back to the root of the project and bootstrap - make bootstrap generator=make build=Debug - make - make doc > build/doc.log From 1d8dcc464df4d4f57af94f3e5efba7fa4b995cf0 Mon Sep 17 00:00:00 2001 From: Martin Taranza Date: Fri, 2 Sep 2016 14:04:17 +0200 Subject: [PATCH 116/185] use int for ERL_VERSION_MAGIC When comparing int to char, char was interpreted as signed. This caused "Invalid control message magic number" --- include/eixx/connect/transport_otp_connection_tcp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 2c4896f..5ccf14c 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -50,7 +50,7 @@ namespace connect { #ifndef HAVE_EI_EPMD // These constants are not exposed by EI headers: -static const char ERL_VERSION_MAGIC = 131; +static const int ERL_VERSION_MAGIC = 131; static const short EPMD_PORT = 4369; static const int EPMDBUF = 512; static const char EI_EPMD_PORT2_REQ = 122; From 49c7ecff1d0ec6a746c3aa11bc6e4155b7771911 Mon Sep 17 00:00:00 2001 From: Martin Taranza Date: Fri, 2 Sep 2016 14:10:49 +0200 Subject: [PATCH 117/185] interpret ip addresses as short and long nodename when trying to get hostname, the first number of IP address was used instead --- src/basic_otp_node_local.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/basic_otp_node_local.cpp b/src/basic_otp_node_local.cpp index 0378f2f..739a007 100644 --- a/src/basic_otp_node_local.cpp +++ b/src/basic_otp_node_local.cpp @@ -86,10 +86,15 @@ void basic_otp_node_local::set_nodename( } std::string short_hostname; + boost::system::error_code ec; + boost::asio::ip::address::from_string( m_hostname, ec ); pos = m_hostname.find('.'); - std::stringstream str; - if (pos != std::string::npos) { + + if(! ec) { + str << m_alivename << '@' << m_hostname; + m_longname = m_alivename+'@'+m_hostname; + } else if (pos != std::string::npos) { str << m_alivename << '@' << m_hostname.substr(0, pos); m_longname = m_alivename+'@'+m_hostname; } else { From 6652a61d6295912b448b1ec64adf04e620ff007d Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 12 Oct 2016 13:15:33 -0400 Subject: [PATCH 118/185] TODO --- TODO | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/TODO b/TODO index f1982b4..ea48e18 100644 --- a/TODO +++ b/TODO @@ -10,3 +10,25 @@ atomic m_rc; union vartype {} m_data; } +4. Protocol change in R19.2. See this report on mailing list (2010-10-12): + Got into interesting 'does not work' situation while connecting newly + deployed c-node (compiled with otp 19.0 libraries) with older 18.3 + erlang node: nodes were unable to communicate with messages + + 2016-10-12 18:43:28.404 [warning] emulator '' got a + corrupted external term from '' on distribution channel ... + + logged on erlang side. + + After some research, root cause was isolated: C-node was initialized using + ei_connect_xinit with random() % 16 for its creation id. In 18.x, Pid of + C-node was encoded as ERL_PID_EXT and used only two lower bits of creation id. + However, in 19.x there is a new Pid wire presentation, ERL_NEW_PID_EXT, which + encodes all 32 bits of creation id. Worse yet, this presentation is + automatically selected for encoding any Pid with creation id > 3, and, + as this presentation is not known by older 18.x nodes, this leads to + connection drop. + + Solution: if you expect your C-nodes to communicate with pre-19.x erlang + nodes, you may use only values 0..3 for creation id. In my case I just + replaced random() % 16 with random() % 4. From 91f0adbf6917bd195ddd8157188471eb576a8d0a Mon Sep 17 00:00:00 2001 From: Dmitriy Kargapolov Date: Fri, 19 Jul 2019 17:31:12 -0400 Subject: [PATCH 119/185] Fix bug - uninitialized cons node field --- include/eixx/marshal/list.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eixx/marshal/list.hxx b/include/eixx/marshal/list.hxx index 4157b7c..7ec30c6 100644 --- a/include/eixx/marshal/list.hxx +++ b/include/eixx/marshal/list.hxx @@ -190,7 +190,7 @@ void list::push_back(const eterm& a) hd->size = 1; hd->alloc_size = 1; cons_t* p = hd->tail; - p->node.set(a); + new (&p->node) eterm(a); p->next = NULL; return; } From c37ab5b92a17094791f57564ebd3daccb7038483 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 10 Jun 2020 21:53:53 -0400 Subject: [PATCH 120/185] Add support for maps. Temporary disable support for a C++ erlang node. --- .vscode/c_cpp_properties.json | 18 ++ .vscode/settings.json | 33 +++ CMakeLists.txt | 3 +- bootstrap.mk | 2 +- build-aux/CMakeInit.txt | 2 +- include/eixx/connect/basic_otp_mailbox.hpp | 3 +- .../connect/transport_otp_connection_tcp.hpp | 1 - include/eixx/eixx.hpp | 2 + include/eixx/eterm.hpp | 2 + include/eixx/marshal/atom.hpp | 20 +- include/eixx/marshal/binary.hpp | 8 +- include/eixx/marshal/binary.hxx | 1 - include/eixx/marshal/defaults.hpp | 7 +- include/eixx/marshal/eterm.hpp | 133 +++++----- include/eixx/marshal/eterm.hxx | 78 +++++- include/eixx/marshal/eterm_format.hpp | 5 +- include/eixx/marshal/eterm_format.hxx | 1 - include/eixx/marshal/eterm_match.hpp | 1 - include/eixx/marshal/list.hpp | 33 +-- include/eixx/marshal/list.hxx | 9 +- include/eixx/marshal/map.hpp | 241 ++++++++++++++++++ include/eixx/marshal/pid.hpp | 12 +- include/eixx/marshal/pid.hxx | 1 - include/eixx/marshal/port.hpp | 7 +- include/eixx/marshal/port.hxx | 1 - include/eixx/marshal/ref.hpp | 13 +- include/eixx/marshal/ref.hxx | 1 - include/eixx/marshal/string.hpp | 4 +- include/eixx/marshal/trace.hpp | 3 +- include/eixx/marshal/tuple.hpp | 28 +- include/eixx/marshal/tuple.hxx | 3 - include/eixx/marshal/var.hpp | 5 +- include/eixx/marshal/varbind.hpp | 6 +- include/eixx/util/atom_table.hpp | 5 +- src/CMakeLists.txt | 29 ++- src/basic_otp_node_local.cpp | 5 + src/server.hpp | 6 + test/CMakeLists.txt | 37 ++- test/test_eterm.cpp | 32 +++ 39 files changed, 611 insertions(+), 190 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json create mode 100644 include/eixx/marshal/map.hpp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..57d835f --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/include", + "/opt/pkg/boost/current/include", + "/opt/sw/erlang/current/lib/erlang/lib/erl_interface-4.0/include" + ], + "defines": [], + "compilerPath": "/usr/bin/clang", + "cStandard": "c18", + "cppStandard": "c++17", + "intelliSenseMode": "clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2177012 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,33 @@ +{ + "files.associations": { + "initializer_list": "cpp", + "valarray": "cpp", + "array": "cpp", + "atomic": "cpp", + "chrono": "cpp", + "list": "cpp", + "vector": "cpp", + "exception": "cpp", + "functional": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "ratio": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp" + }, + "cmake.configureSettings": { + "TOOLCHAIN" : "gcc", + "CMAKE_USER_MAKE_RULES_OVERRIDE" : "${workspaceFolder}/build-aux/CMakeInit.txt", + "CMAKE_INSTALL_PREFIX" : "/opt/pkg/eixx/1.4", + "BOOST_ROOT" : "/opt/pkg/boost/current", + "BOOST_LIBRARYDIR" : "/opt/pkg/boost/current/lib" + }, + "cmake.buildArgs": [ + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index b131f2b..d2ddece 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ project(eixx VERSION 1.4) # CMAKE options customization #=============================================================================== option(VERBOSE "Turn verbosity on|off" OFF) +option(EIXX_MARSHAL_ONLY "Limit build to eterm marshal lib on|off" ON) if(VERBOSE) set(CMAKE_VERBOSE_MAKEFILE ON) @@ -72,8 +73,6 @@ message(STATUS "Configuring for the " #------------------------------------------------------------------------------- # Policies #------------------------------------------------------------------------------- -# Don't curse at non-existing dependencies (since we use code generation) -cmake_policy(SET CMP0046 OLD) # RPATH configuration # =================== diff --git a/bootstrap.mk b/bootstrap.mk index b2aa5a4..3f7fc69 100644 --- a/bootstrap.mk +++ b/bootstrap.mk @@ -124,7 +124,7 @@ bootstrap: | $(DIR) @mkdir -p .build @rm -f inst @[ -L build ] && rm -f build || true - @echo $(call makecmd) > $(DIR)/.cmake + @echo $(call makecmd) > $(DIR)/.cmake.log $(call makecmd) 2>&1 | tee $(DIR)/.cmake.bootstrap.log @[ ! -d build ] && ln -s $(DIR) build || true @ln -s $(prefix) inst diff --git a/build-aux/CMakeInit.txt b/build-aux/CMakeInit.txt index 5cca588..1b4a651 100644 --- a/build-aux/CMakeInit.txt +++ b/build-aux/CMakeInit.txt @@ -4,7 +4,7 @@ SET (CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") SET (CMAKE_C_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g") -SET (CMAKE_CXX_FLAGS_INIT "-Wall -std=c++14 -march=native -Wno-deprecated -Wno-deprecated-declarations") +SET (CMAKE_CXX_FLAGS_INIT "-Wall -std=c++17 -march=native -Wno-deprecated -Wno-deprecated-declarations") SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g -O0") SET (CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") SET (CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index c052ba6..d221769 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -332,7 +332,8 @@ class basic_otp_mailbox } /// Set up a monitor of a remote \a a_target_pid. - const ref& monitor(const epid& a_target_pid) { + //const ref& monitor(const epid& a_target_pid) { + void monitor(const epid& a_target_pid) { if (self() == a_target_pid) return; const ref& l_ref = m_node.send_monitor(self(), a_target_pid); diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 5ccf14c..5507719 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -31,7 +31,6 @@ limitations under the License. #include #include -#include #include diff --git a/include/eixx/eixx.hpp b/include/eixx/eixx.hpp index 54bf6d5..9adb05d 100644 --- a/include/eixx/eixx.hpp +++ b/include/eixx/eixx.hpp @@ -59,7 +59,9 @@ limitations under the License. #endif #include +#if BOOST_VERSION < 106000 #include +#endif #endif // _EIXX_HPP_ diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index 2f57156..21a6497 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -43,6 +43,7 @@ typedef marshal::port port; typedef marshal::ref ref; typedef marshal::tuple tuple; typedef marshal::list list; +typedef marshal::map map; typedef marshal::trace trace; typedef marshal::var var; typedef marshal::varbind varbind; @@ -59,6 +60,7 @@ namespace detail { BOOST_STATIC_ASSERT(sizeof(ref) <= sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(tuple) <= sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(list) <= sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(map) <= sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(trace) <= sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(var) == sizeof(uint64_t)); } // namespace detail diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 29bb664..cccde5d 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -86,29 +86,29 @@ class atom /// Create an atom from the given string. /// @param atom the string to create the atom from. - /// @throws std::runtime_error if atom table is full. - /// @throws err_bad_argument if atom size is longer than MAXATOMLEN - atom(const char* s) throw(std::runtime_error, err_bad_argument) + /// @throw std::runtime_error if atom table is full. + /// @throw err_bad_argument if atom size is longer than MAXATOMLEN + atom(const char* s) : m_index(atom_table().lookup(std::string(s))) {} /// @copydoc atom::atom template - atom(const char (&s)[N]) throw(std::runtime_error, err_bad_argument) + atom(const char (&s)[N]) : m_index(atom_table().lookup(std::string(s, N))) {} /// @copydoc atom::atom - explicit atom(const std::string& s) throw(std::runtime_error) + explicit atom(const std::string& s) : m_index(atom_table().lookup(s)) {} /// @copydoc atom::atom template - explicit atom(const string& s) throw(std::runtime_error) + explicit atom(const string& s) : m_index(atom_table().lookup(std::string(s.c_str(), s.size()))) {} /// @copydoc atom::atom - atom(const char* s, size_t n) throw(std::runtime_error) + atom(const char* s, size_t n) : m_index(atom_table().lookup(std::string(s, n))) {} @@ -119,7 +119,6 @@ class atom /// Decode an atom from a binary buffer encoded in /// Erlang external binary format. atom(const char* a_buf, int& idx, size_t a_size) - throw (err_decode_exception, std::runtime_error) { const char *s = a_buf + idx; const char *s0 = s; @@ -194,10 +193,9 @@ class atom /// @param s is the string representation of the node name that must be /// in the form: \c Alivename@Hostname. /// @return atom representing node name -/// @throws std::runtime_error if atom table is full. -/// @throws err_bad_argument if atom size is longer than MAXNODELEN +/// @throw std::runtime_error if atom table is full. +/// @throw err_bad_argument if atom size is longer than MAXNODELEN inline atom make_node_name(const std::string& s) - throw(std::runtime_error, err_bad_argument) { if (!s.find('@')) throw err_bad_argument("Invalid node name", s); detail::check_node_length(s.size()); diff --git a/include/eixx/marshal/binary.hpp b/include/eixx/marshal/binary.hpp index beafdc6..fa16c8f 100644 --- a/include/eixx/marshal/binary.hpp +++ b/include/eixx/marshal/binary.hpp @@ -45,7 +45,7 @@ class binary { blob* m_blob; - void decode(const char* buf, int& idx, size_t size) throw(err_decode_exception); + void decode(const char* buf, int& idx, size_t size); public: binary() : m_blob(nullptr) {} @@ -87,9 +87,9 @@ class binary * @param buf is the buffer containing Erlang external binary format. * @param idx is the current offset in the buf buffer. * @param size is the size of \a buf buffer. + * @throw err_decode_exception */ - binary(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) - throw(err_decode_exception); + binary(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); /** Get the size of the data (in bytes) */ size_t size() const { return m_blob ? m_blob->size() : 0; } @@ -117,7 +117,7 @@ class binary return size() == rhs.size() && (size() == 0 || memcmp(data(), rhs.data(), size()) == 0); } - bool operator< (const binary& rhs) { + bool operator< (const binary& rhs) const { if (size() < rhs.size()) return true; if (size() > rhs.size()) return false; if (size() == 0) return false; diff --git a/include/eixx/marshal/binary.hxx b/include/eixx/marshal/binary.hxx index cfcc31e..0d62169 100644 --- a/include/eixx/marshal/binary.hxx +++ b/include/eixx/marshal/binary.hxx @@ -35,7 +35,6 @@ namespace marshal { template binary::binary(const char* buf, int& idx, size_t size, const Alloc& a_alloc) - throw (err_decode_exception) { const char* s = buf + idx; const char* s0 = s; diff --git a/include/eixx/marshal/defaults.hpp b/include/eixx/marshal/defaults.hpp index 6d110dd..ca10160 100644 --- a/include/eixx/marshal/defaults.hpp +++ b/include/eixx/marshal/defaults.hpp @@ -68,8 +68,9 @@ namespace eixx { , REF = 10 , TUPLE = 11 , LIST = 12 - , TRACE = 13 - , MAX_ETERM_TYPE = 13 + , MAP = 13 + , TRACE = 14 + , MAX_ETERM_TYPE = 14 }; /// Returns string representation of type \a a_type. @@ -105,6 +106,7 @@ namespace eixx { case VAR : return "VAR"; case TUPLE : return "TUPLE"; case LIST : return "LIST"; + case MAP : return "MAP"; case TRACE : return "TRACE"; default : return "UNDEFINED"; } @@ -124,6 +126,7 @@ namespace eixx { case VAR : return a_prefix ? "::var()" : "var()"; case TUPLE : return a_prefix ? "::tuple()" : "tuple()"; case LIST : return a_prefix ? "::list()" : "list()"; + case MAP : return a_prefix ? "::map()" : "map()"; case TRACE : return a_prefix ? "::trace()" : "trace()"; default : return ""; } diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 642e186..7d8edcb 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -29,10 +29,7 @@ limitations under the License. #ifndef _EIXX_MARSHAL_ETERM_HPP_ #define _EIXX_MARSHAL_ETERM_HPP_ -#include -#include -#include -#include +#include #include @@ -46,6 +43,7 @@ limitations under the License. #include #include #include +#include #include #include #include @@ -56,19 +54,20 @@ namespace marshal { namespace { template struct enum_type; - template struct enum_type { typedef long type; }; - template struct enum_type { typedef double type; }; - template struct enum_type { typedef bool type; }; - template struct enum_type { typedef atom type; }; - template struct enum_type, Alloc> { typedef string type; }; - template struct enum_type, Alloc> { typedef binary type; }; - template struct enum_type, Alloc> { typedef epid type; }; - template struct enum_type, Alloc> { typedef port type; }; - template struct enum_type, Alloc> { typedef ref type; }; - template struct enum_type { typedef var type; }; - template struct enum_type, Alloc> { typedef tuple type; }; - template struct enum_type, Alloc> { typedef list type; }; - template struct enum_type, Alloc> { typedef trace type; }; + template struct enum_type { using type = long ; }; + template struct enum_type { using type = double ; }; + template struct enum_type { using type = bool ; }; + template struct enum_type { using type = atom ; }; + template struct enum_type, Alloc> { using type = string; }; + template struct enum_type, Alloc> { using type = binary; }; + template struct enum_type, Alloc> { using type = epid ; }; + template struct enum_type, Alloc> { using type = port ; }; + template struct enum_type, Alloc> { using type = ref ; }; + template struct enum_type { using type = var ; }; + template struct enum_type, Alloc> { using type = tuple ; }; + template struct enum_type, Alloc> { using type = list ; }; + template struct enum_type, Alloc> { using type = map ; }; + template struct enum_type, Alloc> { using type = trace ; }; } /** @@ -141,6 +140,7 @@ class eterm { ref r; tuple t; list l; + map m; trace trc; uint64_t value; // this is for ease of copying @@ -170,6 +170,7 @@ class eterm { vartype(const ref& x) : r(x) {} vartype(const tuple& x) : t(x) {} vartype(const list& x) : l(x) {} + vartype(const map& x) : m(x) {} vartype(const trace& x) : trc(x) {} vartype() : i(0) {} @@ -184,9 +185,9 @@ class eterm { /** * Decode a term from the Erlang external binary format. + * @throw err_decode_exception */ - void decode(const char* a_buf, int& idx, size_t a_size, const Alloc& a_alloc) - throw (err_decode_exception); + void decode(const char* a_buf, int& idx, size_t a_size, const Alloc& a_alloc); long& get(long*) { check(LONG); return vt.i; } double& get(double*) { check(DOUBLE); return vt.d; } @@ -200,6 +201,7 @@ class eterm { ref& get(const ref*) { check(REF); return vt.r; } tuple& get(const tuple*) { check(TUPLE); return vt.t; } list& get(const list*) { check(LIST); return vt.l; } + map& get(const map*) { check(MAP); return vt.m; } trace& get(const trace*) { check(TRACE); return vt.trc; } template friend T& get(eterm
& t); @@ -211,11 +213,12 @@ class eterm { a->vt.reset(); } - static eterm format(const Alloc& a_alloc, const char** fmt, va_list* args) - throw (err_format_exception); + /// @throw err_format_exception + static eterm format(const Alloc& a_alloc, const char** fmt, va_list* args); + /// @throw err_format_exception static void format(const Alloc& a_alloc, atom& m, atom& f, eterm& args, - const char** fmt, va_list* pa) throw (err_format_exception); + const char** fmt, va_list* pa); public: eterm_type type() const { return m_type; } const char* type_string() const; @@ -237,12 +240,13 @@ class eterm { : m_type(STRING), vt(string(a.c_str(), a.size(), alloc)) {} eterm(const string& a) : m_type(STRING), vt(a) {} eterm(const binary& a) : m_type(BINARY), vt(a) {} - eterm(const epid& a) : m_type(PID), vt(a) {} - eterm(const port& a) : m_type(PORT), vt(a) {} - eterm(const ref& a) : m_type(REF), vt(a) {} - eterm(const tuple& a) : m_type(TUPLE), vt(a) {} - eterm(const list& a) : m_type(LIST), vt(a) {} - eterm(const trace& a) : m_type(TRACE), vt(a) {} + eterm(const epid& a) : m_type(PID), vt(a) {} + eterm(const port& a) : m_type(PORT), vt(a) {} + eterm(const ref& a) : m_type(REF), vt(a) {} + eterm(const tuple& a) : m_type(TUPLE), vt(a) {} + eterm(const list& a) : m_type(LIST), vt(a) {} + eterm(const map& a) : m_type(MAP), vt(a) {} + eterm(const trace& a) : m_type(TRACE), vt(a) {} /** * Tuple initialization @@ -258,8 +262,7 @@ class eterm { * @param a_size is the total size of the term stored in \a a_buf buffer. * @param a_alloc is the custom allocator. */ - eterm(const char* a_buf, size_t a_size, const Alloc& a_alloc = Alloc()) - throw(err_decode_exception); + eterm(const char* a_buf, size_t a_size, const Alloc& a_alloc = Alloc()); /** * Construct a term by decoding it from an \a idx offset of the @@ -270,8 +273,7 @@ class eterm { * @param a_size is the total size of the term stored in \a a_buf buffer. * @param a_alloc is the custom allocator. */ - eterm(const char* a_buf, int& idx, size_t a_size, const Alloc& a_alloc = Alloc()) - throw(err_decode_exception) { + eterm(const char* a_buf, int& idx, size_t a_size, const Alloc& a_alloc = Alloc()) { decode(a_buf, idx, a_size, a_alloc); } @@ -288,6 +290,7 @@ class eterm { case REF: { new (&vt.r) ref(a.vt.r); break; } case TUPLE: { new (&vt.t) tuple(a.vt.t); break; } case LIST: { new (&vt.l) list(a.vt.l); break; } + case MAP: { new (&vt.m) map(a.vt.m); break; } case TRACE: { new (&vt.trc) trace(a.vt.trc); break; } default: vt.value = a.vt.value; @@ -318,6 +321,7 @@ class eterm { case REF: { vt.r.~ref(); return; } case TUPLE: { vt.t.~tuple(); return; } case LIST: { vt.l.~list(); return; } + case MAP: { vt.m.~map(); return; } case TRACE: { vt.trc.~trace(); return; } default: return; } @@ -349,6 +353,14 @@ class eterm { } #endif + /** + * Check that one term is less than the other. The function returns true + * if the term's type is less than the type of term "rhs" accorting to + * type_precedence() or if they have identical precedence, the check is + * made that the terms value is less than the value of the "rhs" term. + */ + bool operator<(const eterm& rhs) const; + template void set(const T& a) { if (m_type >= STRING) @@ -420,11 +432,13 @@ class eterm { const binary& to_binary() const { check(BINARY); return vt.bin; } const epid& to_pid() const { check(PID); return vt.pid; } const port& to_port() const { check(PORT); return vt.prt; } - const ref& to_ref() const { check(REF); return vt.r; } - const tuple& to_tuple() const { check(TUPLE); return vt.t; } - tuple& to_tuple() { check(TUPLE); return vt.t; } - const list& to_list() const { check(LIST); return vt.l; } - list& to_list() { check(LIST); return vt.l; } + const ref& to_ref() const { check(REF); return vt.r; } + const tuple& to_tuple() const { check(TUPLE); return vt.t; } + tuple& to_tuple() { check(TUPLE); return vt.t; } + const list& to_list() const { check(LIST); return vt.l; } + list& to_list() { check(LIST); return vt.l; } + const map& to_map() const { check(MAP); return vt.m; } + map& to_map() { check(MAP); return vt.m; } const trace& to_trace() const { check(TRACE); return vt.trc; } trace& to_trace() { check(TRACE); return vt.trc; } @@ -456,6 +470,7 @@ class eterm { bool is_var() const { return m_type == VAR ; } bool is_tuple() const { return m_type == TUPLE ; } bool is_list() const { return m_type == LIST ; } + bool is_map() const { return m_type == MAP ; } bool is_trace() const { return m_type == TRACE ; } /** @@ -464,15 +479,15 @@ class eterm { * @param binding varbind to use in pattern matching. * This binding will be updated with new bound variables if * match succeeds. + * @throw err_unbound_variable * @return true if matching succeeded or false if failed. */ bool match(const eterm& pattern, varbind* binding, - const Alloc& a_alloc = Alloc()) const - throw (err_unbound_variable); + const Alloc& a_alloc = Alloc()) const; // Separated into a separate function without default args for ease of gdb debugging - bool match(const eterm& pattern) const - throw (err_unbound_variable) { return match(pattern, NULL, Alloc()); } + /// @throw err_unbound_variable + bool match(const eterm& pattern) const { return match(pattern, NULL, Alloc()); } /** * Returns the equivalent without inner variables, using the @@ -487,15 +502,16 @@ class eterm { * err_unbound_variable if there is a variable. * @returns a smart pointer to the new term with all eterm_var * variables replaced by bound values. - * @throws err_invalid_term if the term is invalid - * @throws err_unbound_variable if a variable is unbound + * @throw err_invalid_term if the term is invalid + * @throw err_unbound_variable if a variable is unbound */ - bool subst(eterm& out, const varbind* binding) const - throw (err_invalid_term, err_unbound_variable); + bool subst(eterm& out, const varbind* binding) const; - /** Substitutes all variables in the term \a a. */ - eterm apply(const varbind& binding) const - throw (err_invalid_term, err_unbound_variable); + /** Substitutes all variables in the term \a a. + * @throw err_invalid_term + * @throw err_unbound_variable + */ + eterm apply(const varbind& binding) const; /** * This method finds the first unbound variable in a term for @@ -535,10 +551,10 @@ class eterm { * @param a_header_size is the size of packet header (valid values: 0, 1, 2, 4). * @param a_with_version indicates if a magic version byte * needs to be encoded in the beginning of the buffer. + * @throw err_encode_exception */ void encode(char* buf, size_t size, - size_t a_header_size = DEF_HEADER_SIZE, bool a_with_version = true) const - throw (err_encode_exception); + size_t a_header_size = DEF_HEADER_SIZE, bool a_with_version = true) const; /** * Create an eterm from an string representation. Like sprintf() @@ -563,21 +579,19 @@ class eterm { * "alex", 40, eterm_t("1955-10-1")); * * @return compiled eterm - * @throws err_format_exception + * @throw err_format_exception */ - static eterm format(const Alloc& a_alloc, const char* fmt, ...) - throw (err_format_exception); - static eterm format(const char* fmt, ...) - throw (err_format_exception); + static eterm format(const Alloc& a_alloc, const char* fmt, ...); + static eterm format(const char* fmt, ...); /** * Same as format(a_alloc, fmt, ...), but parses string in format: * "Module:Function(Arg1, Arg2, ...) + * @throw err_format_exception */ static void format(const Alloc& a_alloc, atom& mod, atom& fun, eterm& args, - const char* fmt, ...) throw (err_format_exception); - static void format(atom& mod, atom& fun, eterm& args, const char* fmt, ...) - throw (err_format_exception); + const char* fmt, ...); + static void format(atom& mod, atom& fun, eterm& args, const char* fmt, ...); /// Cast a value to eterm. If t is of eterm type, it is returned as is. template @@ -602,12 +616,13 @@ class eterm { case REF: return wrapper(v, vt.r); case TUPLE: return wrapper(v, vt.t); case LIST: return wrapper(v, vt.l); + case MAP: return wrapper(v, vt.m); case TRACE: return wrapper(v, vt.trc); default: { std::stringstream s; s << "Undefined term_type (" << m_type << ')'; throw err_invalid_term(s.str()); } - BOOST_STATIC_ASSERT(MAX_ETERM_TYPE == 13); + BOOST_STATIC_ASSERT(MAX_ETERM_TYPE == 14); } } }; diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index 993f8c8..63e76cd 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -88,6 +88,9 @@ inline eterm_type type_string_to_type(const char* s, size_t n) { case 'l': if (strncmp(p,"ist",m) == 0) r = LIST; break; + case 'm': + if (strncmp(p,"ap",m) == 0) r = MAP; + break; default: break; } @@ -112,9 +115,10 @@ const char* eterm::type_string() const { case VAR: return "var"; case TUPLE: return "tuple"; case LIST: return "list"; + case MAP: return "map"; case TRACE: return "trace"; } - BOOST_STATIC_ASSERT(MAX_ETERM_TYPE == 13); + static_assert(MAX_ETERM_TYPE == 14); } template @@ -134,13 +138,64 @@ inline bool eterm::operator== (const eterm& rhs) const { case REF: return vt.r == rhs.vt.r; case TUPLE: return vt.t == rhs.vt.t; case LIST: return vt.l == rhs.vt.l; + case MAP: return vt.m == rhs.vt.m; case TRACE: return vt.trc == rhs.vt.trc; default: { std::stringstream s; s << "Undefined term_type (" << m_type << ')'; throw err_invalid_term(s.str()); } } - BOOST_STATIC_ASSERT(MAX_ETERM_TYPE == 13); + static_assert(MAX_ETERM_TYPE == 14); +} + +template +inline bool eterm::operator< (const eterm& rhs) const { + /// Term comparison precedence + auto type_precedence = [](int type) { + static const int s_precedences[MAX_ETERM_TYPE+1] = { + 9, // UNDEFINED + 0, 0, // LONG, DOUBLE + 1, // BOOL + 2, // ATOM + 13, // VAR + 10, // STRING + 11, // BINARY + 6, // PID + 5, // PORT + 3, // REF + 7, // TUPLE + 10, // LIST + 8, // MAP + 12 // TRACE + }; + return s_precedences[type]; + }; + int a = type_precedence(int(m_type)); + int b = type_precedence(int(rhs.m_type)); + if (a < b) return true; + if (a > b) return false; + // precedences are equal - (note that numeric types have same precedence): + switch (m_type) { + case LONG: return double(vt.i) < (rhs.m_type == LONG ? double(rhs.vt.i) : rhs.vt.d); + case DOUBLE: return vt.d < (rhs.m_type == LONG ? double(rhs.vt.i) : rhs.vt.d); + case BOOL: return vt.b < rhs.vt.b; + case ATOM: return vt.a < rhs.vt.a; + case VAR: return vt.v < rhs.vt.v; + case STRING: return vt.s < rhs.vt.s; + case BINARY: return vt.bin < rhs.vt.bin; + case PID: return vt.pid < rhs.vt.pid; + case PORT: return vt.prt < rhs.vt.prt; + case REF: return vt.r < rhs.vt.r; + case TUPLE: return vt.t < rhs.vt.t; + case LIST: return vt.l < rhs.vt.l; + case MAP: return vt.m < rhs.vt.m; + case TRACE: return vt.trc < rhs.vt.trc; + default: { + std::stringstream s; s << "Undefined term_type (" << m_type << ')'; + throw err_invalid_term(s.str()); + } + } + static_assert(MAX_ETERM_TYPE == 14); } template @@ -157,7 +212,6 @@ std::string eterm::to_string(size_t a_size_limit, const varbind* b template eterm::eterm(const char* a_buf, size_t a_size, const Alloc& a_alloc) - throw(err_decode_exception) { int idx = 0; int vsn; @@ -168,7 +222,6 @@ eterm::eterm(const char* a_buf, size_t a_size, const Alloc& a_alloc) template void eterm::decode(const char* a_buf, int& idx, size_t a_size, const Alloc& a_alloc) - throw(err_decode_exception) { if ((size_t)idx == a_size) throw err_decode_exception("Empty term", idx); @@ -240,6 +293,10 @@ void eterm::decode(const char* a_buf, int& idx, size_t a_size, const Allo new (this) eterm(port(a_buf, idx, a_size, a_alloc)); break; + case ERL_MAP_EXT: + new (this) eterm(map(a_buf, idx, a_size, a_alloc)); + break; + default: std::ostringstream oss; oss << "Unknown message content type " << type; @@ -268,7 +325,7 @@ string eterm::encode(size_t a_header_size, bool a_with_version) co template void eterm::encode(char* a_buf, size_t size, - size_t a_header_size, bool a_with_version) const throw (err_encode_exception) + size_t a_header_size, bool a_with_version) const { #if BOOST_VERSION >= 104900 namespace bd = boost::spirit::detail; @@ -309,7 +366,6 @@ bool eterm::match( const eterm& pattern, varbind* binding, const Alloc& a_alloc) const - throw (err_unbound_variable) { // Protect the given binding. Change it only if the match succeeds. varbind dirty(a_alloc); @@ -329,7 +385,6 @@ bool eterm::match( template bool eterm::subst(eterm& out, const varbind* binding) const - throw (err_invalid_term, err_unbound_variable) { visit_eterm_subst visitor(out, binding); return visitor.apply_visitor(*this); @@ -337,7 +392,6 @@ bool eterm::subst(eterm& out, const varbind* binding) const template eterm eterm::apply(const varbind& binding) const - throw (err_invalid_term, err_unbound_variable) { eterm out; visit_eterm_subst visitor(out, &binding); @@ -347,7 +401,6 @@ eterm eterm::apply(const varbind& binding) const template eterm eterm::format(const Alloc& a_alloc, const char** fmt, va_list* pap) - throw (err_format_exception) { try { return eformat(fmt, pap, a_alloc); @@ -361,7 +414,7 @@ eterm eterm::format(const Alloc& a_alloc, const char** fmt, va_lis template void eterm::format(const Alloc& a_alloc, atom& m, atom& f, eterm& args, - const char** fmt, va_list* pap) throw (err_format_exception) + const char** fmt, va_list* pap) { try { eformat(m, f, args, fmt, pap, a_alloc); @@ -375,7 +428,6 @@ void eterm::format(const Alloc& a_alloc, atom& m, atom& f, eterm& template eterm eterm::format(const Alloc& a_alloc, const char* fmt, ...) - throw (err_format_exception) { va_list ap; va_start(ap, fmt); @@ -385,7 +437,6 @@ eterm eterm::format(const Alloc& a_alloc, const char* fmt, ...) template eterm eterm::format(const char* fmt, ...) - throw (err_format_exception) { va_list ap; va_start(ap, fmt); @@ -395,7 +446,7 @@ eterm eterm::format(const char* fmt, ...) template void eterm::format(const Alloc& a_alloc, atom& m, atom& f, eterm& args, - const char* fmt, ...) throw (err_format_exception) + const char* fmt, ...) { va_list ap; va_start(ap, fmt); @@ -404,7 +455,6 @@ void eterm::format(const Alloc& a_alloc, atom& m, atom& f, eterm& } template void eterm::format(atom& m, atom& f, eterm& args, const char* fmt, ...) - throw (err_format_exception) { va_list ap; va_start(ap, fmt); diff --git a/include/eixx/marshal/eterm_format.hpp b/include/eixx/marshal/eterm_format.hpp index 209f855..e5a01f9 100644 --- a/include/eixx/marshal/eterm_format.hpp +++ b/include/eixx/marshal/eterm_format.hpp @@ -50,13 +50,14 @@ namespace marshal { */ // Forward declaration +/// @throw err_format_exception template -static eterm eformat(const char** fmt, va_list* args, const Alloc& a_alloc = Alloc()) - throw(err_format_exception); +static eterm eformat(const char** fmt, va_list* args, const Alloc& a_alloc = Alloc()); /** * Parse a format string in the form "Module:Function(Args...)" into corresponding * \a mod, \a fun, \a args + * @throw err_format_exception */ template static void eformat(atom& mod, atom& fun, eterm& args, diff --git a/include/eixx/marshal/eterm_format.hxx b/include/eixx/marshal/eterm_format.hxx index 8ef7e8b..6c9c61a 100644 --- a/include/eixx/marshal/eterm_format.hxx +++ b/include/eixx/marshal/eterm_format.hxx @@ -342,7 +342,6 @@ namespace marshal { template static eterm eformat(const char** fmt, va_list* pap, const Alloc& a_alloc) - throw (err_format_exception) { vector v(a_alloc); Alloc alloc(a_alloc); diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index e7f326f..de84716 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -273,7 +273,6 @@ class eterm_pattern_action { bool operator() (const eterm& a_term, varbind* a_binding) const - throw (eterm_exception) { varbind binding; if (a_binding) diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 0c471c9..3b6205b 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -26,8 +26,7 @@ limitations under the License. ***** END LICENSE BLOCK ***** */ -#ifndef _IMPL_LIST_HPP_ -#define _IMPL_LIST_HPP_ +#pragma once #include #include @@ -161,8 +160,7 @@ class list : protected alloc_base, Alloc> { a.m_blob = nullptr; } - explicit list(const cons_t* a_head, int a_len = -1, const Alloc& alloc = Alloc()) - throw (err_bad_argument); + explicit list(const cons_t* a_head, int a_len = -1, const Alloc& alloc = Alloc()); template list(const eterm (&items)[N], const Alloc& alloc = Alloc()) @@ -177,8 +175,7 @@ class list : protected alloc_base, Alloc> { /** * Decode the list from a binary buffer. */ - explicit list(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) - throw(err_decode_exception); + explicit list(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); ~list() { release(); @@ -212,7 +209,7 @@ class list : protected alloc_base, Alloc> { /// Return pointer to the N'th element in the list. This method has /// O(N) complexity. - const eterm& nth(size_t n) const throw(err_bad_argument) { + const eterm& nth(size_t n) const { if (n > length()) throw err_bad_argument("Index out of bounds", n); size_t i = 0; @@ -221,7 +218,7 @@ class list : protected alloc_base, Alloc> { return *it; } - list tail(size_t idx) const throw(err_bad_argument); + list tail(size_t idx) const; list& operator= (const list& rhs) { BOOST_ASSERT(rhs.initialized()); @@ -241,6 +238,16 @@ class list : protected alloc_base, Alloc> { return it1 == end1 && it2 == end2; } + bool operator< (const list& rhs) const { + const_iterator it1 = begin(), it2 = rhs.begin(), + end1 = end(), end2 = rhs.end(); + for(; it1 != end1 && it2 != end2; ++it1, ++it2) { + if (!(*it1 < *it2)) + return false; + } + return it1 == end1 && it2 != end2; + } + size_t encode_size() const { if (length() == 0) return 1; @@ -256,11 +263,9 @@ class list : protected alloc_base, Alloc> { void encode(char* buf, int& idx, size_t size) const; - bool subst(eterm& out, const varbind* binding) const - throw (err_unbound_variable); + bool subst(eterm& out, const varbind* binding) const; - bool match(const eterm& pattern, varbind* binding) const - throw (err_invalid_term, err_unbound_variable); + bool match(const eterm& pattern, varbind* binding) const; std::ostream& dump(std::ostream& out, const varbind* vars = NULL) const; @@ -382,6 +387,4 @@ namespace std { } // namespace std -#include - -#endif // _IMPL_LIST_HPP_ +#include \ No newline at end of file diff --git a/include/eixx/marshal/list.hxx b/include/eixx/marshal/list.hxx index 7ec30c6..772df61 100644 --- a/include/eixx/marshal/list.hxx +++ b/include/eixx/marshal/list.hxx @@ -25,7 +25,6 @@ limitations under the License. ***** END LICENSE BLOCK ***** */ -#pragma once #include #include @@ -65,7 +64,7 @@ void list::init(const eterm* items, size_t N, const Alloc& alloc) template list::list(const cons_t* a_head, int a_len, const Alloc& alloc) - throw (err_bad_argument) : base_t(alloc) + : base_t(alloc) { unsigned int alloc_size; @@ -105,7 +104,7 @@ list::list(const cons_t* a_head, int a_len, const Alloc& alloc) template list::list(const char *buf, int& idx, size_t size, const Alloc& a_alloc) - throw(err_decode_exception) : base_t(a_alloc) + : base_t(a_alloc) { int arity; if (ei_decode_list_header(buf, &idx, &arity) < 0) @@ -165,7 +164,7 @@ void list::encode(char* buf, int& idx, size_t size) const } template -list list::tail(size_t idx) const throw(err_bad_argument) +list list::tail(size_t idx) const { const header_t* l_header = header(); const cons_t* p = l_header->head; @@ -208,7 +207,6 @@ void list::push_back(const eterm& a) template bool list::subst(eterm& out, const varbind* binding) const - throw (err_unbound_variable) { // We check if any contained term changes. bool changed = false; @@ -242,7 +240,6 @@ bool list::subst(eterm& out, const varbind* binding) const template bool list::match(const eterm& pattern, varbind* binding) const - throw (err_invalid_term, err_unbound_variable) { switch (pattern.type()) { case VAR: return pattern.match(eterm(*this), binding); diff --git a/include/eixx/marshal/map.hpp b/include/eixx/marshal/map.hpp new file mode 100644 index 0000000..3af2f61 --- /dev/null +++ b/include/eixx/marshal/map.hpp @@ -0,0 +1,241 @@ +//---------------------------------------------------------------------------- +/// \file map.hpp +//---------------------------------------------------------------------------- +/// \brief A class implementing an map object of Erlang external term format. +//---------------------------------------------------------------------------- +// Copyright (c) 2020 Serge Aleynikov +// Created: 2020-06-10 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +Copyright 2010 Serge Aleynikov + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +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. + +***** END LICENSE BLOCK ***** +*/ +#ifndef _IMPL_MAP_HPP_ +#define _IMPL_MAP_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace eixx { +namespace marshal { + +template class eterm; + +template +class map { +public: + using MapAlloc = typename Alloc::rebind, eterm>>::other; + using MapT = std::map, eterm, std::less>, MapAlloc>; +protected: + blob* m_blob; + + void release() { release(m_blob); m_blob = nullptr; } + + void release(blob* p) { + if (p && p->release(false)) { + p->data()->~MapT(); + p->free(); + } + } + + void initialize(const Alloc& alloc = Alloc()) { + m_blob = new blob(1, alloc); + auto* m = m_blob->data(); + new (m) MapT(); + } +public: + using const_iterator = typename MapT::const_iterator; + using iterator = typename MapT::iterator; + + static const map& null() { static map s = map(Alloc()); return s; } + + explicit map(std::nullptr_t) : m_blob(nullptr) {} + + map(const Alloc& a = Alloc()) { + initialize(a); + } + + map(const map& s) : m_blob(s.m_blob) { + if (m_blob) m_blob->inc_rc(); + } + + map(map&& s) : m_blob(s.m_blob) { + s.m_blob = nullptr; + } + + map(std::initializer_list,eterm>> items, const Alloc& alloc = Alloc()) { + initialize(alloc); + auto* m = m_blob->data(); + for (auto& pair : items) + m->insert(pair); + } + + map(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) { + int arity; + if (ei_decode_map_header(buf, &idx, &arity) < 0) + err_decode_exception("Error decoding tuple header", idx); + initialize(a_alloc); + auto* m = m_blob->data(); + for (int i=0; i < arity; i++) { + auto key = eterm(buf, idx, size, a_alloc); + auto val = eterm(buf, idx, size, a_alloc); + m->emplace(std::make_pair(key, val)); + } + BOOST_ASSERT((size_t)idx <= size); + } + + ~map() { + release(); + } + + map& operator= (const map& s) { + if (this != &s) { + release(); + m_blob = s.m_blob; + if (m_blob) m_blob->inc_rc(); + } + return *this; + } + + map& operator= (map&& s) { + if (this != &s) { + release(); + m_blob = s.m_blob; + s.m_blob = nullptr; + } + return *this; + } + + const eterm& operator[](const eterm& key) const { + static const eterm s_undefined = am_undefined; + if (!m_blob) return s_undefined; + auto it = m_blob->data()->find(key); + return (it == m_blob->data()->end()) ? s_undefined : it->second; + } + + void insert(const eterm& key, const eterm& val) { + if (!m_blob) initialize(); + m_blob->data()->insert(std::make_pair(key, val)); + } + + void erase(const eterm& key) { + if (!m_blob) return; + m_blob->data()->erase(key); + } + + const_iterator begin() const { return m_blob ? m_blob->data()->cbegin() : null().begin(); } + const_iterator end() const { return m_blob ? m_blob->data()->cend() : null().end(); } + + size_t size() const { return m_blob ? m_blob->data()->size() : 0; } + bool empty() const { return !m_blob || m_blob->data()->empty(); } + + void clear() { if (m_blob) m_blob->data().clear(); } + + // Use only for debugging + int use_count() const { return m_blob ? m_blob->use_count() : -1000000; } + + bool operator== (const map& rhs) const { + if (size() != rhs.size()) return false; + auto it1 = begin(); + auto it2 = rhs.begin(); + auto end1 = end(); + for (; it1 != end1; ++it1, ++it2) + if (!(*it1 == *it2)) + return false; + return true; + } + + bool operator< (const map& rhs) const { + if (size() < rhs.size()) return true; + if (size() > rhs.size()) return false; + BOOST_ASSERT(size() == rhs.size()); + auto it1 = begin(); + auto it2 = rhs.begin(); + auto end1 = end(); + for (; it1 != end1; ++it1, ++it2) { + // 1. Is key1 < key2? + if (it1->first < it2->first) + return true; + if (it2->first < it1->first) + return false; + // 1. Is value1 < value2? + if (it1->second < it2->second) + return true; + if (it2->second < it1->second) + return false; + } + return size() == 0; + } + + /** Size of buffer needed to hold the encoded map. */ + size_t encode_size() const { + BOOST_ASSERT(m_blob); + size_t result = 5; + for (const_iterator it = begin(), iend = end(); it != iend; ++it) { + result += visit_eterm_encode_size_calc().apply_visitor(it->first); // key + result += visit_eterm_encode_size_calc().apply_visitor(it->second); // value + } + return result; + } + + void encode(char* buf, int& idx, size_t size) const { + BOOST_ASSERT(m_blob); + ei_encode_map_header(buf, &idx, this->size()); + for(auto it = begin(), iend=end(); it != iend; ++it) { + visit_eterm_encoder key_visitor(buf, idx, size); + key_visitor.apply_visitor(it->first); + visit_eterm_encoder val_visitor(buf, idx, size); + val_visitor.apply_visitor(it->second); + } + BOOST_ASSERT((size_t)idx <= size); + } + + std::ostream& dump(std::ostream& out, const varbind* binding=NULL) const { + out << "#{"; + for(auto it = begin(), first=begin(), iend=end(); it != iend; ++it) { + out << (it != first ? "," : ""); + visit_eterm_stringify key_visitor(out, binding); + key_visitor.apply_visitor(it->first); + out << " => "; + visit_eterm_stringify val_visitor(out, binding); + val_visitor.apply_visitor(it->second); + } + return out << '}'; + } +}; + +} // namespace marshal +} // namespace eixx + +namespace std { + + template + ostream& operator<< (ostream& out, const eixx::marshal::map& m) { return m.dump(out); } + +} + +//#include + +#endif // _IMPL_MAP_HPP_ diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index 3a0b4ef..fb811cf 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -90,7 +90,6 @@ class epid { // Must only be called from constructor! void init(const atom& node, int id, uint8_t creation, const Alloc& alloc) - throw(err_bad_argument) { m_blob = new blob(1, alloc); new (m_blob->data()) pid_blob(node, id, creation); @@ -100,8 +99,9 @@ class epid { #endif } - void decode(const char* buf, int& idx, size_t size, const Alloc& a_alloc) - throw (err_decode_exception, err_bad_argument); + /// @throw err_decode_exception + /// @throw err_bad_argument + void decode(const char* buf, int& idx, size_t size, const Alloc& a_alloc); public: @@ -122,25 +122,21 @@ class epid { * @throw err_bad_argument if node is empty or greater than MAX_NODE_LENGTH **/ epid(const char* node, int id, int serial, int creation, const Alloc& a_alloc = Alloc()) - throw(err_bad_argument) : epid(atom(node), id, serial, creation, a_alloc) {} epid(const atom& node, int id, int serial, int creation, const Alloc& a_alloc = Alloc()) - throw(err_bad_argument) : epid(node, (id & 0x7fff) | ((serial & 0x1fff) << 15), creation, a_alloc) {} epid(const atom& node, int id, int creation, const Alloc& a_alloc = Alloc()) - throw(err_bad_argument) { detail::check_node_length(node.size()); init(node, id, creation, a_alloc); } /// Decode the pid from a binary buffer. - epid(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) - throw (err_decode_exception, err_bad_argument) { + epid(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) { decode(buf, idx, size, a_alloc); } diff --git a/include/eixx/marshal/pid.hxx b/include/eixx/marshal/pid.hxx index db77c76..22a1863 100644 --- a/include/eixx/marshal/pid.hxx +++ b/include/eixx/marshal/pid.hxx @@ -34,7 +34,6 @@ namespace marshal { template void epid::decode(const char *buf, int& idx, size_t size, const Alloc& alloc) - throw(err_decode_exception, err_bad_argument) { const char* s = buf + idx; const char* s0 = s; diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index 8660bd0..dd98928 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -63,7 +63,7 @@ class port { // Must only be called from constructor! void init(const atom& node, int id, uint8_t creation, - const Alloc& alloc) throw(err_bad_argument) + const Alloc& alloc) { m_blob = new blob(1, alloc); new (m_blob->data()) port_blob(node, id & 0x0fffffff, creation & 0x03); @@ -86,7 +86,6 @@ class port { * @throw err_bad_argument if node is empty or greater than MAX_NODE_LENGTH **/ port(const char* node, const int id, const int creation, const Alloc& a_alloc = Alloc()) - throw (err_bad_argument) { size_t n = strlen(node); detail::check_node_length(n); @@ -95,7 +94,6 @@ class port { } port(const atom& node, const int id, const int creation, const Alloc& a_alloc = Alloc()) - throw (err_bad_argument) { detail::check_node_length(node.size()); init(node, id, creation, a_alloc); @@ -109,8 +107,7 @@ class port { * @param size is the size of the \a buf buffer. * @param a_alloc is the allocator to use. */ - port(const char *buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) - throw (err_decode_exception); + port(const char *buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); port(const port& rhs) : m_blob(rhs.m_blob) { if (m_blob) m_blob->inc_rc(); } port(port&& rhs) : m_blob(rhs.m_blob) { rhs.m_blob = nullptr; } diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index a14e6c3..717bb19 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -34,7 +34,6 @@ namespace marshal { template port::port(const char *buf, int& idx, size_t size, const Alloc& a_alloc) - throw(err_decode_exception) { const char* s = buf + idx; const char* s0 = s; diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index cfa0e5a..b9c95d0 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -73,7 +73,7 @@ class ref { // Must only be called from constructor! void init(const atom& a_node, uint32_t a_id0, uint64_t a_id1, uint8_t a_cre, - const Alloc& alloc) throw(err_bad_argument) + const Alloc& alloc) { m_blob = new blob(1, alloc); new (m_blob->data()) ref_blob(a_node, a_id0, a_id1, a_cre); @@ -110,26 +110,26 @@ class ref { */ template ref(const char* node, uint32_t (&ids)[N], unsigned int creation, - const Alloc& a_alloc = Alloc()) throw(err_bad_argument) + const Alloc& a_alloc = Alloc()) : ref(atom(node), ids[0], ids[1], ids[2], creation, a_alloc) {} template ref(const atom& node, uint32_t (&ids)[N], unsigned int creation, - const Alloc& a_alloc = Alloc()) throw(err_bad_argument) + const Alloc& a_alloc = Alloc()) : ref(node, ids[0], ids[1], ids[2], creation, a_alloc) { BOOST_STATIC_ASSERT(N == 3); } ref(const atom& node, uint32_t id0, uint32_t id1, uint32_t id2, unsigned int creation, - const Alloc& a_alloc = Alloc()) throw(err_bad_argument) + const Alloc& a_alloc = Alloc()) : ref(node, id0, id1 | ((uint64_t)id2 << 32), creation, a_alloc) {} // For internal use ref(const atom& node, uint32_t id0, uint64_t id1, uint8_t creation, - const Alloc& a_alloc = Alloc()) throw(err_bad_argument) + const Alloc& a_alloc = Alloc()) { detail::check_node_length(node.size()); init(node, id0, id1, creation, a_alloc); @@ -143,8 +143,7 @@ class ref { * @param size is the size of the \a buf buffer. * @param a_alloc is the allocator to use. */ - ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) - throw(err_decode_exception); + ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); ref(const ref& rhs) : m_blob(rhs.m_blob) { if (m_blob) m_blob->inc_rc(); } ref(ref&& rhs) : m_blob(rhs.m_blob) { rhs.m_blob = nullptr; } diff --git a/include/eixx/marshal/ref.hxx b/include/eixx/marshal/ref.hxx index 6bc8321..50cfe4c 100644 --- a/include/eixx/marshal/ref.hxx +++ b/include/eixx/marshal/ref.hxx @@ -36,7 +36,6 @@ namespace marshal { template ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) - throw(err_decode_exception) { const char *s = buf + idx; const char *s0 = s; diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index 7eeb84a..48c9f0e 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -105,8 +105,7 @@ class string s.m_blob = nullptr; } - string(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) - throw(err_decode_exception); + string(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); ~string() { release(); @@ -199,7 +198,6 @@ static std::string to_binary_string(const string& a) { template string::string(const char* buf, int& idx, size_t size, const Alloc& a_alloc) - throw(err_decode_exception) { const char *s = buf + idx; const char *s0 = s; diff --git a/include/eixx/marshal/trace.hpp b/include/eixx/marshal/trace.hpp index 3a3a6f2..0fd42bb 100644 --- a/include/eixx/marshal/trace.hpp +++ b/include/eixx/marshal/trace.hpp @@ -78,7 +78,6 @@ class trace : protected tuple { /// Decode the pid from a binary buffer. trace(const char* buf, int& idx, size_t a_size, const Alloc& a_alloc = Alloc()) - throw (err_decode_exception) : tuple(buf, idx, a_size, a_alloc) { if (size() != 5 || (*this)[0].type() != LONG @@ -120,7 +119,7 @@ class trace : protected tuple { } bool operator< (const trace& rhs) const { - return static_cast&>(this) < static_cast&>(rhs); + return *static_cast*>(this) < static_cast&>(rhs); } size_t encode_size() const { return tuple::encode_size(); } diff --git a/include/eixx/marshal/tuple.hpp b/include/eixx/marshal/tuple.hpp index a139b5f..5da7fa9 100644 --- a/include/eixx/marshal/tuple.hpp +++ b/include/eixx/marshal/tuple.hpp @@ -86,7 +86,10 @@ class tuple { explicit tuple(size_t arity, const Alloc& alloc = Alloc()) : m_blob(new blob, Alloc>(arity+1, alloc)) { + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wclass-memaccess" memset(m_blob->data(), 0, sizeof(eterm)*m_blob->size()); + #pragma GCC diagnostic pop set_init_size(0); } @@ -117,8 +120,7 @@ class tuple { /** * Decode the tuple from a binary buffer. */ - tuple(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) - throw(err_decode_exception); + tuple(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); ~tuple() { release(); @@ -156,6 +158,20 @@ class tuple { return true; } + bool operator< (const tuple& rhs) const { + if (size() < rhs.size()) + return true; + if (size() > rhs.size()) + return false; + for(const_iterator it1 = begin(), + it2 = rhs.begin(), iend = end(); it1 != iend; ++it1, ++it2) + { + if (!(*it1 < *it2)) + return false; + } + return true; + } + const eterm& operator[] (int idx) const { BOOST_ASSERT(m_blob && (size_t)idx < size()); return m_blob->data()[idx]; @@ -167,7 +183,7 @@ class tuple { } template - void push_back(const T& t) throw (err_invalid_term) { + void push_back(const T& t) { BOOST_ASSERT(m_blob); if (initialized()) throw err_invalid_term("Attempt to change immutable tuple!"); @@ -195,11 +211,9 @@ class tuple { void encode(char* buf, int& idx, size_t size) const; - bool subst(eterm& out, const varbind* binding) const - throw (err_unbound_variable); + bool subst(eterm& out, const varbind* binding) const; - bool match(const eterm& pattern, varbind* binding) const - throw (err_invalid_term, err_unbound_variable); + bool match(const eterm& pattern, varbind* binding) const; std::ostream& dump(std::ostream& out, const varbind* vars = NULL) const; diff --git a/include/eixx/marshal/tuple.hxx b/include/eixx/marshal/tuple.hxx index 8ac0047..8310b4c 100644 --- a/include/eixx/marshal/tuple.hxx +++ b/include/eixx/marshal/tuple.hxx @@ -38,7 +38,6 @@ namespace marshal { template tuple::tuple(const char* buf, int& idx, size_t size, const Alloc& a_alloc) - throw(err_decode_exception) { int arity; if (ei_decode_tuple_header(buf, &idx, &arity) < 0) @@ -65,7 +64,6 @@ void tuple::encode(char* buf, int& idx, size_t size) const template bool tuple::subst(eterm& out, const varbind* binding) const - throw (err_unbound_variable) { // We check if any contained term changes. bool changed = false; @@ -92,7 +90,6 @@ bool tuple::subst(eterm& out, const varbind* binding) const template bool tuple::match(const eterm& pattern, varbind* binding) const - throw (err_invalid_term, err_unbound_variable) { switch (pattern.type()) { case VAR: return pattern.match(eterm(*this), binding); diff --git a/include/eixx/marshal/var.hpp b/include/eixx/marshal/var.hpp index 0d0fc2b..9dd0ed9 100644 --- a/include/eixx/marshal/var.hpp +++ b/include/eixx/marshal/var.hpp @@ -86,6 +86,9 @@ class var template bool operator==(const T&) const { return false; } + template + bool operator<(const T&) const { return false; } + size_t encode_size() const { throw err_encode_exception("Cannot encode vars!"); } void encode(char* buf, int& idx, size_t size) const { @@ -100,7 +103,6 @@ class var template bool subst(eterm& out, const varbind* binding) const - throw (err_unbound_variable) { const eterm* term = binding ? binding->find(name()) : NULL; if (!term || !check_type(*term)) @@ -111,7 +113,6 @@ class var template bool match(const eterm& pattern, varbind* binding) const - throw (err_unbound_variable) { if (is_any()) return true; if (!binding) return false; diff --git a/include/eixx/marshal/varbind.hpp b/include/eixx/marshal/varbind.hpp index 55561fd..e48b4f0 100644 --- a/include/eixx/marshal/varbind.hpp +++ b/include/eixx/marshal/varbind.hpp @@ -129,17 +129,17 @@ class varbind { } const eterm* - operator[] (const char* a_var_name) const throw(err_unbound_variable) { + operator[] (const char* a_var_name) const { return (*this)[atom(a_var_name)]; } const eterm* - operator[] (const string& a_var_name) const throw(err_unbound_variable) { + operator[] (const string& a_var_name) const { return (*this)[atom(a_var_name)]; } const eterm* - operator[] (atom a_var_name) const throw(err_unbound_variable) { + operator[] (atom a_var_name) const { const eterm* p = find(a_var_name); if (!p) throw err_unbound_variable(a_var_name.c_str()); return p; diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 1020eb2..70a1605 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -107,12 +107,11 @@ namespace util { /// Lookup an atom in the atom table by name. If the atom is not /// present in the atom table - add it. Return the index of the /// atom in the atom table. - /// @throws std::runtime_error if atom table is full. - /// @throws err_bad_argument if atom size is longer than MAXATOMLEN + /// @throw std::runtime_error if atom table is full. + /// @throw err_bad_argument if atom size is longer than MAXATOMLEN int lookup(const char* a_name, size_t n) { return lookup(String(a_name, n)); } int lookup(const char* a_name) { return lookup(String(a_name)); } int lookup(const String& a_name) - throw(std::runtime_error, err_bad_argument) { if (a_name.size() == 0) return 0; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f89f7b9..a625b85 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,10 +2,15 @@ list(APPEND EIXX_SRCS am.cpp - basic_otp_node_local.cpp - test_node.cpp ) +if (NOT EIXX_MARSHAL_ONLY) + list(APPEND EIXX_SRCS + basic_otp_node_local.cpp + test_node.cpp + ) +endif() + add_library(${PROJECT_NAME} SHARED ${EIXX_SRCS}) add_library(${PROJECT_NAME}_static STATIC ${EIXX_SRCS}) set_target_properties(${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) @@ -22,9 +27,11 @@ endif() set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) -add_executable(test-node test_node.cpp) -target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) -target_link_libraries(test-node eixx pthread) +if (NOT EIXX_MARSHAL_ONLY) + add_executable(test-node test_node.cpp) + target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) + target_link_libraries(test-node eixx pthread) +endif() # In the install below we split library installation in a separate library clause # so that it's possible to build/install both Release and Debug versions of the @@ -53,8 +60,10 @@ if (${CMAKE_BUILD_TYPE} STREQUAL "release") ) endif() -install( - TARGETS - test-node - RUNTIME DESTINATION test -) +if (NOT EIXX_MARSHAL_ONLY) + install( + TARGETS + test-node + RUNTIME DESTINATION test + ) +endif() \ No newline at end of file diff --git a/src/basic_otp_node_local.cpp b/src/basic_otp_node_local.cpp index 739a007..e01fa5d 100644 --- a/src/basic_otp_node_local.cpp +++ b/src/basic_otp_node_local.cpp @@ -17,6 +17,9 @@ limitations under the License. ***** END LICENSE BLOCK ***** */ +#include + +#if BOOST_VERSION < 106500 #include #include @@ -123,3 +126,5 @@ void basic_otp_node_local::set_nodename( } // namespace connect } // namespace eixx + +#endif // BOOST_VERSION \ No newline at end of file diff --git a/src/server.hpp b/src/server.hpp index 064d130..48d2ef2 100644 --- a/src/server.hpp +++ b/src/server.hpp @@ -10,6 +10,10 @@ #pragma once +#include + +#if BOOST_VERSION < 106500 + #include #include #include @@ -337,3 +341,5 @@ class uds_server : public server< Handler > }; } // namespace eixx + +#endif // BOOST_VERSION \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bd96aa6..7ed9119 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -7,10 +7,15 @@ list(APPEND TEST_SRCS test_eterm_match.cpp test_eterm_pool.cpp test_eterm_refc.cpp - test_mailbox.cpp - test_node.cpp ) +if (NOT EIXX_MARSHAL_ONLY) + list(APPEND TEST_SRCS + test_mailbox.cpp + test_node.cpp + ) +endif() + # This must be AFTER link_directories add_executable(test-eterm ${TEST_SRCS}) target_compile_definitions(test-eterm PRIVATE -DBOOST_TEST_DYN_LINK) @@ -24,15 +29,6 @@ target_link_libraries( boost_system ) -add_executable(test-connect test_async_queue.cpp) -target_link_libraries( - test-connect - boost_unit_test_framework - eixx - ${Erlang_EI_LIBRARIES} - ${Boost_LIBRARIES} -) - add_executable(test-perf test_perf.cpp) target_link_libraries( test-perf @@ -41,8 +37,25 @@ target_link_libraries( ${Boost_LIBRARIES} ) +if (NOT EIXX_MARSHAL_ONLY) + add_executable(test-connect test_async_queue.cpp) + target_link_libraries( + test-connect + boost_unit_test_framework + eixx + ${Erlang_EI_LIBRARIES} + ${Boost_LIBRARIES} + ) + + install( + TARGETS + test-eterm test-perf + RUNTIME DESTINATION test + ) +endif() + install( TARGETS - test-eterm test-connect test-perf + test-eterm test-perf RUNTIME DESTINATION test ) diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 35ecab2..ab394e9 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -391,6 +391,37 @@ BOOST_AUTO_TEST_CASE( test_pid ) } } +BOOST_AUTO_TEST_CASE( test_map ) +{ + allocator_t alloc; + { + map m00, m01; + BOOST_REQUIRE_EQUAL(m00, m01); + + map m{{1, 2.00}, {"abc", 10}}; + BOOST_REQUIRE_EQUAL(2ul, m.size()); + BOOST_REQUIRE_EQUAL(2.00, m[1].to_double()); + BOOST_REQUIRE_EQUAL(10, m["abc"].to_long()); + + map m1{{1, 2.00}, {"abc", 10}}; + BOOST_REQUIRE_EQUAL(m, m1); + + map m2{{1, 3.00}, {"abc", 10}}; + BOOST_REQUIRE_LT(m, m2); + } + { + // #{1=>2, a => 3} + const uint8_t buf[] = {ERL_MAP_EXT,0,0,0,2,97,1,97,2,100,0,1,97,97,3}; + int i = 0; + eterm term((const char*)buf, i, sizeof(buf), alloc); + BOOST_REQUIRE_EQUAL(15, i); + BOOST_REQUIRE(term.is_map()); + BOOST_REQUIRE_EQUAL(2, term.to_map().size()); + BOOST_REQUIRE_EQUAL(2, term.to_map()[1].to_long()); + BOOST_REQUIRE_EQUAL(3, term.to_map()[atom("a")].to_long()); + } +} + BOOST_AUTO_TEST_CASE( test_less_then ) { { @@ -403,6 +434,7 @@ BOOST_AUTO_TEST_CASE( test_less_then ) std::set(); std::set(); std::set(); + std::set(); } { From 1c85a30e025cb3c98aa398d05e30beb681c37bfc Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 10 Jun 2020 22:51:55 -0400 Subject: [PATCH 121/185] Update Travis script --- .travis.yml | 73 ++++++++++++----------------------- .vscode/c_cpp_properties.json | 3 +- 2 files changed, 27 insertions(+), 49 deletions(-) diff --git a/.travis.yml b/.travis.yml index fb52185..e1fae45 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,41 +2,32 @@ language: cpp compiler: g++ language: erlang otp_release: - - 18.1 -addons: - apt: - sources: - - ubuntu-toolchain-r-test - - boost-latest - packages: - - gcc-4.9 - - g++-4.9 - - libboost1.55-all-dev - - cmake - - cmake-data - - libxslt1.1 - - python-lxml - - graphviz - - doxygen + - 23.0 + +matrix: + include: + - os: linux + addons: + apt: + update: true + sources: + - sourceline: 'ppa:mhier/libboost-latest' + - sourceline: 'ppa:ubuntu-toolchain-r/test' + packages: + - gcc-9 + - g++-9 + #- boost-latest + - boost1.70 + #- cmake + #- cmake-data + - libxslt1.1 + - python-lxml + - doxygen + env: + - MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" before_install: - - lsb_release -a - - uname -a - - sudo apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ trusty main restricted" - - sudo add-apt-repository -y "deb http://ppa.launchpad.net/dns/gnu/ubuntu precise main" - - sudo add-apt-repository -y "deb http://ppa.launchpad.net/wnoronha/thrift/ubuntu precise main" - - sudo add-apt-repository -y "deb http://ppa.launchpad.net/kzemek/boost/ubuntu utopic main" - - sudo add-apt-repository ppa:george-edison55/precise-backports --yes - - sudo apt-get update -qq - - # sudo apt-get install libboost1.55-all-dev - - # sudo updatedb - - # dpkg -S /usr/include/boost/version.hpp - - # sudo dpkg -L libboost1.55-all-dev - - # find /usr/include/boost -print | head -100 - - # grep BOOST_LIB_VERSION /usr/include/boost/version.hpp | grep define - - # locate libboost | head -100 - - # sudo apt-get install -qq libthrift-dev libthrift0 thrift-compiler - - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 90 + - eval "${MATRIX_EVAL}" before_script: - echo "DIR:BUILD=/tmp/${USER}/utxx" > .cmake-args.$(hostname) @@ -46,24 +37,10 @@ before_script: - echo "BOOST_LIBRARYDIR=/usr/lib/x86_64-linux-gnu" >> .cmake-args.$(hostname) - g++ --version script: - ############################################################################ - # All the dependencies are installed in ${TRAVIS_BUILD_DIR}/deps/ - ############################################################################ - - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" - - mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR} - + - ${CXX} --version ############################################################################ # Install a recent CMake (unless already installed on OS X) ############################################################################ - - | - if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then - CMAKE_URL="http://www.cmake.org/files/v3.5/cmake-3.5.2-Linux-x86_64.tar.gz" - mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake - export PATH=${DEPS_DIR}/cmake/bin:${PATH} - else - if ! brew ls --version cmake &>/dev/null; then brew install cmake; fi - fi - - cd ${TRAVIS_BUILD_DIR} # Go back to the root of the project and bootstrap - make bootstrap generator=make build=Debug - make diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 57d835f..9ede467 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -11,7 +11,8 @@ "compilerPath": "/usr/bin/clang", "cStandard": "c18", "cppStandard": "c++17", - "intelliSenseMode": "clang-x64" + "intelliSenseMode": "clang-x64", + "compileCommands": "${workspaceFolder}/build/compile_commands.json" } ], "version": 4 From 2d8c3d7d64f61ae3930ff585f828bf0af5f9948b Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 10 Jun 2020 23:00:26 -0400 Subject: [PATCH 122/185] Update Travis script --- .travis.yml | 3 ++- .vscode/launch.json | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 .vscode/launch.json diff --git a/.travis.yml b/.travis.yml index e1fae45..913683d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,8 @@ before_script: - echo "PKG_ROOT_DIR=/usr/local" >> .cmake-args.$(hostname) - echo "BOOST_INCLUDEDIR=/usr/include" >> .cmake-args.$(hostname) - echo "BOOST_LIBRARYDIR=/usr/lib/x86_64-linux-gnu" >> .cmake-args.$(hostname) - - g++ --version + - echo "CMAKE_CXX_COMPILER=${CXX}" >> .cmake-args.$(hostname) + script: - ${CXX} --version ############################################################################ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3b910af --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,29 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "test-eterm", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/test/test-eterm", + "args": ["-t", "test_map"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + //"preLaunchTask": "C/C++: g++ build active file", + "miDebuggerPath": "/usr/bin/gdb" + } + ] +} \ No newline at end of file From 773b42893a279ad5ef66a841e3c580c46453cd61 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 10 Jun 2020 23:05:01 -0400 Subject: [PATCH 123/185] Fix issue with gcc 9.3 compiler --- include/eixx/marshal/map.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eixx/marshal/map.hpp b/include/eixx/marshal/map.hpp index 3af2f61..b4b2391 100644 --- a/include/eixx/marshal/map.hpp +++ b/include/eixx/marshal/map.hpp @@ -46,7 +46,7 @@ template class eterm; template class map { public: - using MapAlloc = typename Alloc::rebind, eterm>>::other; + using MapAlloc = typename Alloc::template rebind, eterm>>::other; using MapT = std::map, eterm, std::less>, MapAlloc>; protected: blob* m_blob; From 79de377da051e1c74805b823e0f8f10eb1a7d039 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 10 Jun 2020 23:09:36 -0400 Subject: [PATCH 124/185] Fix issue with gcc 9.3 compiler --- include/eixx/marshal/eterm.hxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index 63e76cd..43d8ed8 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -118,7 +118,7 @@ const char* eterm::type_string() const { case MAP: return "map"; case TRACE: return "trace"; } - static_assert(MAX_ETERM_TYPE == 14); + static_assert(MAX_ETERM_TYPE == 14, "Invalid number of terms"); } template @@ -145,7 +145,7 @@ inline bool eterm::operator== (const eterm& rhs) const { throw err_invalid_term(s.str()); } } - static_assert(MAX_ETERM_TYPE == 14); + static_assert(MAX_ETERM_TYPE == 14, "Invalid number of terms"); } template @@ -195,7 +195,7 @@ inline bool eterm::operator< (const eterm& rhs) const { throw err_invalid_term(s.str()); } } - static_assert(MAX_ETERM_TYPE == 14); + static_assert(MAX_ETERM_TYPE == 14, "Invalid number of terms"); } template From 8a92e0df492a69eb42136b9bf44896d86f8bfaac Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Sat, 27 Jun 2020 11:25:21 -0400 Subject: [PATCH 125/185] Update for support of GCC 10.1 --- .vscode/c_cpp_properties.json | 3 +- .vscode/settings.json | 7 +- .vscode/tasks.json | 26 ++++++++ bootstrap.mk | 1 + include/eixx/eterm_exception.hpp | 28 ++++---- include/eixx/marshal/atom.hpp | 2 +- include/eixx/marshal/eterm.hpp | 96 ++++++++++++++++----------- include/eixx/marshal/eterm_format.hxx | 7 +- include/eixx/marshal/eterm_match.hpp | 12 ++-- include/eixx/marshal/list.hpp | 8 +-- include/eixx/marshal/map.hpp | 13 ++-- include/eixx/marshal/tuple.hpp | 4 ++ include/eixx/marshal/var.hpp | 7 +- include/eixx/marshal/varbind.hpp | 6 +- test/test_eterm_refc.cpp | 36 +++++----- 15 files changed, 163 insertions(+), 93 deletions(-) create mode 100644 .vscode/tasks.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 9ede467..6913c39 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -12,7 +12,8 @@ "cStandard": "c18", "cppStandard": "c++17", "intelliSenseMode": "clang-x64", - "compileCommands": "${workspaceFolder}/build/compile_commands.json" + "compileCommands": "${workspaceFolder}/build/compile_commands.json", + "configurationProvider": "ms-vscode.cmake-tools" } ], "version": 4 diff --git a/.vscode/settings.json b/.vscode/settings.json index 2177012..0878f6d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,10 +24,11 @@ "cmake.configureSettings": { "TOOLCHAIN" : "gcc", "CMAKE_USER_MAKE_RULES_OVERRIDE" : "${workspaceFolder}/build-aux/CMakeInit.txt", - "CMAKE_INSTALL_PREFIX" : "/opt/pkg/eixx/1.4", - "BOOST_ROOT" : "/opt/pkg/boost/current", - "BOOST_LIBRARYDIR" : "/opt/pkg/boost/current/lib" + "CMAKE_INSTALL_PREFIX" : "/opt/pkg/eixx/1.4" }, "cmake.buildArgs": [ + ], + "cmake.preferredGenerators": [ + "Unix Makefiles" ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..6f87cd5 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,26 @@ +{ + "tasks": [ + { + "type": "shell", + "label": "C/C++: g++ build active file", + "command": "/usr/bin/g++", + "args": [ + "-g", + "${file}", + "-o", + "${fileDirname}/${fileBasenameNoExtension}" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + } + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/bootstrap.mk b/bootstrap.mk index 3f7fc69..dbc60d9 100644 --- a/bootstrap.mk +++ b/bootstrap.mk @@ -84,6 +84,7 @@ info: @echo "OPT_FILE: $(OPT_FILE)" @echo "BLD_DIR: $(BLD_DIR)" @echo "DIR: $(DIR)" + @echo "TOOLCHAIN: $(toolchain)" @echo "build: $(BUILD)" @echo "prefix: $(prefix)" @echo "generator: $(generator)" diff --git a/include/eixx/eterm_exception.hpp b/include/eixx/eterm_exception.hpp index 286c344..6bd9b07 100644 --- a/include/eixx/eterm_exception.hpp +++ b/include/eixx/eterm_exception.hpp @@ -124,38 +124,40 @@ class err_unbound_variable: public eterm_exception { class err_format_exception: public eterm_exception { const char* m_pos; const char* m_start; + std::string m_what; public: err_format_exception( - const std::string &msg, const char* pos, const char* start = nullptr) + const std::string& msg, const char* pos, const char* start = nullptr) : eterm_exception(msg) , m_pos(pos) , m_start(start) - {} - - const char* what() const throw() { + { std::stringstream s; s << m_msg << " (" << (m_pos - m_start) << ")."; - return s.str().c_str(); + m_what = s.str(); } - const char* pos() const { return m_pos; } - void start(const char* a_start) { m_start = a_start; } + + const char* what() const throw() { return m_what.c_str(); } + const char* pos() const { return m_pos; } + void start(const char* a_start) { m_start = a_start; } }; /** * Exception while encoding */ class err_encode_exception: public eterm_exception { - int m_code; + int m_code; + std::string m_what; public: err_encode_exception(const std::string &msg, int code=0) : eterm_exception(msg) , m_code(code) - {} - - const char* what() const throw() { + { std::stringstream s; s << m_msg << " (" << m_code << ")."; - return s.str().c_str(); + m_what = s.str(); } - int code() const { return m_code; } + + const char* what() const throw() { return m_what.c_str(); } + int code() const { return m_code; } }; /** diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index cccde5d..55bd2aa 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -81,7 +81,7 @@ class atom /// Create an empty atom atom() : m_index(0) { - BOOST_STATIC_ASSERT(sizeof(atom) == 4); + static_assert(sizeof(atom) == 4, "Invalid atom size!"); } /// Create an atom from the given string. diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 7d8edcb..fd9fb46 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -126,7 +126,7 @@ namespace { template class eterm { eterm_type m_type; - +public: union vartype { double d; bool b; @@ -173,13 +173,23 @@ class eterm { vartype(const map& x) : m(x) {} vartype(const trace& x) : trc(x) {} + vartype(string&& x) : s(std::move(x)) {} + vartype(binary&& x) : bin(std::move(x)) {} + vartype(epid&& x) : pid(std::move(x)) {} + vartype(port&& x) : prt(std::move(x)) {} + vartype(ref&& x) : r(std::move(x)) {} + vartype(tuple&& x) : t(std::move(x)) {} + vartype(list&& x) : l(std::move(x)) {} + vartype(map&& x) : m(std::move(x)) {} + vartype(trace&& x) : trc(std::move(x)) {} + vartype() : i(0) {} ~vartype() {} void reset() { i = 0; } } vt; - BOOST_STATIC_ASSERT(sizeof(vartype) == sizeof(uint64_t)); + static_assert(sizeof(vartype) == sizeof(uint64_t), "Invalid class size!"); void check(eterm_type tp) const { if (unlikely(m_type != tp)) throw err_wrong_type(tp, m_type); } @@ -206,11 +216,12 @@ class eterm { template friend T& get(eterm& t); + void reset() { m_type = UNDEFINED; vt.reset(); } + void replace(eterm* a) { m_type = a->m_type; vt.value = a->vt.value; - a->m_type = UNDEFINED; - a->vt.reset(); + a->reset(); } /// @throw err_format_exception @@ -223,7 +234,9 @@ class eterm { eterm_type type() const { return m_type; } const char* type_string() const; - eterm() : m_type(UNDEFINED) {} + eterm() : m_type(UNDEFINED) { + static_assert(sizeof(eterm)==2*sizeof(uint64_t), "Invalid size!"); + } eterm(unsigned int a) : m_type(LONG), vt((int)a) {} eterm(unsigned long a) : m_type(LONG), vt((long)a) {} @@ -248,9 +261,40 @@ class eterm { eterm(const map& a) : m_type(MAP), vt(a) {} eterm(const trace& a) : m_type(TRACE), vt(a) {} + eterm(string&& a) : m_type(STRING), vt(std::move(a)) {} + eterm(binary&& a) : m_type(BINARY), vt(std::move(a)) {} + eterm(epid&& a) : m_type(PID), vt(std::move(a)) {} + eterm(port&& a) : m_type(PORT), vt(std::move(a)) {} + eterm(ref&& a) : m_type(REF), vt(std::move(a)) {} + eterm(tuple&& a) : m_type(TUPLE), vt(std::move(a)) {} + eterm(list&& a) : m_type(LIST), vt(std::move(a)) {} + eterm(map&& a) : m_type(MAP), vt(std::move(a)) {} + eterm(trace&& a) : m_type(TRACE), vt(std::move(a)) {} + /** - * Tuple initialization + * Copy construct a term from another one. The term is copied by value + * and for compound terms the storage is reference counted. */ + eterm(const eterm& a) : m_type(a.m_type) { + switch (m_type) { + case STRING: { new (&vt.s) string(a.vt.s); break; } + case BINARY: { new (&vt.bin) binary(a.vt.bin); break; } + case PID: { new (&vt.pid) epid(a.vt.pid); break; } + case PORT: { new (&vt.prt) port(a.vt.prt); break; } + case REF: { new (&vt.r) ref(a.vt.r); break; } + case TUPLE: { new (&vt.t) tuple(a.vt.t); break; } + case LIST: { new (&vt.l) list(a.vt.l); break; } + case MAP: { new (&vt.m) map(a.vt.m); break; } + case TRACE: { new (&vt.trc) trace(a.vt.trc); break; } + default: + vt.value = a.vt.value; + } + } + + /// Move constructor + eterm(eterm&& a) { replace(&a); } + + /// Tuple initialization eterm(std::initializer_list> items, const Alloc& alloc = Alloc()) : eterm(tuple(items, alloc)) {} @@ -277,35 +321,6 @@ class eterm { decode(a_buf, idx, a_size, a_alloc); } - /** - * Copy construct a term from another one. The term is copied by value - * and for compound terms the storage is reference counted. - */ - eterm(const eterm& a) : m_type(a.m_type) { - switch (m_type) { - case STRING: { new (&vt.s) string(a.vt.s); break; } - case BINARY: { new (&vt.bin) binary(a.vt.bin); break; } - case PID: { new (&vt.pid) epid(a.vt.pid); break; } - case PORT: { new (&vt.prt) port(a.vt.prt); break; } - case REF: { new (&vt.r) ref(a.vt.r); break; } - case TUPLE: { new (&vt.t) tuple(a.vt.t); break; } - case LIST: { new (&vt.l) list(a.vt.l); break; } - case MAP: { new (&vt.m) map(a.vt.m); break; } - case TRACE: { new (&vt.trc) trace(a.vt.trc); break; } - default: - vt.value = a.vt.value; - } - } - - /** - * Move constructor - */ -#if __cplusplus >= 201103L - eterm(eterm&& a) { - replace(&a); - } -#endif - /** * Destruct this term. For compound terms it decreases the * reference count of their storage. This does nothing to @@ -342,16 +357,19 @@ class eterm { * Assign the value to this term. If current term has been initialized, * its old value is destructed. */ -#if __cplusplus >= 201103L eterm& operator= (eterm&& a) { if (this != &a) { - if (m_type >= STRING) - this->~eterm(); + if (m_type >= STRING) this->~eterm(); replace(&a); } return *this; } -#endif + + template + void operator= (T&& a) { + if (m_type >= STRING) this->~eterm(); + new (this) eterm(std::move(a)); + } /** * Check that one term is less than the other. The function returns true diff --git a/include/eixx/marshal/eterm_format.hxx b/include/eixx/marshal/eterm_format.hxx index 6c9c61a..b6bf3ad 100644 --- a/include/eixx/marshal/eterm_format.hxx +++ b/include/eixx/marshal/eterm_format.hxx @@ -57,8 +57,11 @@ namespace marshal { namespace { template - struct vector : public std::vector, Alloc> { - typedef std::vector, Alloc> base; + struct vector : public + std::vector, + typename Alloc::template rebind>::other> { + using VecAlloc = typename Alloc::template rebind>::other; + using base = std::vector, VecAlloc>; explicit vector(const Alloc& a_alloc = Alloc()) : base(a_alloc) {} diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index de84716..dc2b63b 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -52,12 +52,12 @@ class eterm_pattern_action; */ template class eterm_pattern_matcher { - std::list, Alloc> m_pattern_list; - std::list< eterm_pattern_action< Alloc >, Alloc > it; + using ListAlloc = typename Alloc::template + rebind>::other; public: - typedef std::list, Alloc> list_t; - typedef typename list_t::const_iterator const_iterator; - typedef typename list_t::iterator iterator; + using list_t = std::list, ListAlloc>; + using const_iterator = typename list_t::const_iterator; + using iterator = typename list_t::iterator; struct init_struct { eterm p; @@ -195,6 +195,8 @@ class eterm_pattern_matcher { } return res; } +private: + list_t m_pattern_list; }; /** diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 3b6205b..e1c434e 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -118,8 +118,8 @@ class list : protected alloc_base, Alloc> { class iterator; typedef const iterator const_iterator; - iterator begin() { iterator it(empty() ? NULL : head()); return it; } - iterator end() { return iterator::end(); } + iterator begin() { iterator it(empty() ? NULL : head()); return it; } + iterator end() { return iterator::end(); } const_iterator begin() const { const_iterator it(empty() ? NULL : head()); return it; } const_iterator end() const { return iterator::end(); } @@ -177,9 +177,7 @@ class list : protected alloc_base, Alloc> { */ explicit list(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); - ~list() { - release(); - } + ~list() { release(); } /** * Add a term to list. Tuples added must be fully filled diff --git a/include/eixx/marshal/map.hpp b/include/eixx/marshal/map.hpp index b4b2391..1a575a3 100644 --- a/include/eixx/marshal/map.hpp +++ b/include/eixx/marshal/map.hpp @@ -49,11 +49,13 @@ class map { using MapAlloc = typename Alloc::template rebind, eterm>>::other; using MapT = std::map, eterm, std::less>, MapAlloc>; protected: - blob* m_blob; + using BlobT = blob; + + BlobT* m_blob; void release() { release(m_blob); m_blob = nullptr; } - void release(blob* p) { + void release(BlobT* p) { if (p && p->release(false)) { p->data()->~MapT(); p->free(); @@ -61,7 +63,7 @@ class map { } void initialize(const Alloc& alloc = Alloc()) { - m_blob = new blob(1, alloc); + m_blob = new BlobT(1, alloc); auto* m = m_blob->data(); new (m) MapT(); } @@ -73,7 +75,8 @@ class map { explicit map(std::nullptr_t) : m_blob(nullptr) {} - map(const Alloc& a = Alloc()) { + explicit map(const Alloc& a = Alloc()) { + static_assert(sizeof(map) == sizeof(void*), "Invalid class size!"); initialize(a); } @@ -85,7 +88,7 @@ class map { s.m_blob = nullptr; } - map(std::initializer_list,eterm>> items, const Alloc& alloc = Alloc()) { + map(std::initializer_list,eterm>> items, const Alloc& alloc = Alloc()) { initialize(alloc); auto* m = m_blob->data(); for (auto& pair : items) diff --git a/include/eixx/marshal/tuple.hpp b/include/eixx/marshal/tuple.hpp index 5da7fa9..d0af77f 100644 --- a/include/eixx/marshal/tuple.hpp +++ b/include/eixx/marshal/tuple.hpp @@ -86,10 +86,14 @@ class tuple { explicit tuple(size_t arity, const Alloc& alloc = Alloc()) : m_blob(new blob, Alloc>(arity+1, alloc)) { + #ifndef __clang__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wclass-memaccess" + #endif memset(m_blob->data(), 0, sizeof(eterm)*m_blob->size()); + #ifndef __clang__ #pragma GCC diagnostic pop + #endif set_init_size(0); } diff --git a/include/eixx/marshal/var.hpp b/include/eixx/marshal/var.hpp index 9dd0ed9..5a75d54 100644 --- a/include/eixx/marshal/var.hpp +++ b/include/eixx/marshal/var.hpp @@ -59,7 +59,12 @@ class var eterm_type set(eterm_type t) { return m_name == am_ANY_ ? UNDEFINED : t; } public: - var(eterm_type t = UNDEFINED) : var(am_ANY_, t) {} + var(eterm_type t = UNDEFINED) + : var(am_ANY_, t) + { + static_assert(sizeof(var) == sizeof(uint64_t), "Invalid class size!"); + } + var(const atom& s, eterm_type t = UNDEFINED) : m_name(s) { m_type = set(t); } var(const char* s, eterm_type t = UNDEFINED) : var(atom(s), t) {} diff --git a/include/eixx/marshal/varbind.hpp b/include/eixx/marshal/varbind.hpp index e48b4f0..a6c4503 100644 --- a/include/eixx/marshal/varbind.hpp +++ b/include/eixx/marshal/varbind.hpp @@ -71,7 +71,11 @@ class varbind { std::ostream& out, const varbind& binding); protected: - typedef std::map, std::less, Alloc> eterm_map_t; + using eterm_map_t = + std::map< + atom, eterm, std::less, + typename Alloc::template rebind>>::other + >; public: explicit varbind(const Alloc& a_alloc = Alloc()) diff --git a/test/test_eterm_refc.cpp b/test/test_eterm_refc.cpp index 37b606f..cdf7786 100644 --- a/test/test_eterm_refc.cpp +++ b/test/test_eterm_refc.cpp @@ -36,22 +36,23 @@ struct counted_alloc : public std::allocator { template counted_alloc(const _T&) {} - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - - template struct rebind { - typedef counted_alloc<_T> other; + using pointer = T*; + using const_pointer = T const*; + using reference = T&; + using const_reference = T const&; + using value_type = T; + + template struct rebind { + using other = counted_alloc; }; void construct(pointer p, const T& value) { ::new((void*)p) T(value); } - pointer allocate(size_t sz) { + pointer allocate(size_t n) { ++g_alloc_count; - return static_cast(::operator new(sz * sizeof(T))); + return static_cast(::operator new(n * sizeof(T))); } void deallocate(pointer p, size_t sz) { @@ -59,7 +60,7 @@ struct counted_alloc : public std::allocator { ::operator delete(p); } - void destroy(pointer __p) { __p->~T(); } + void destroy(pointer p) { p->~T(); } }; BOOST_AUTO_TEST_CASE( test_refc_format ) @@ -90,7 +91,7 @@ BOOST_AUTO_TEST_CASE( test_refc_format ) BOOST_AUTO_TEST_CASE( test_refc_pool_format ) { - typedef boost::pool_allocator my_alloc; + using my_alloc = boost::pool_allocator; my_alloc alloc; { for (int i=0; i < 10; i++) { @@ -111,25 +112,26 @@ BOOST_AUTO_TEST_CASE( test_refc_pool_format ) BOOST_AUTO_TEST_CASE( test_refc_list ) { - typedef counted_alloc my_alloc; + using my_alloc = counted_alloc; + using term = eterm; my_alloc alloc; list lst(nullptr); // Allocates static global empty list BOOST_CHECK_EQUAL(2, g_alloc_count); { - eterm term = list({1, 2, 3}, alloc); + term et = list({1, 2, 3}, alloc); BOOST_CHECK_EQUAL(4, g_alloc_count); // 1 for blob_t, 1 for blob's data - auto term2 = term; + auto am = et; BOOST_CHECK_EQUAL(4, g_alloc_count); } BOOST_CHECK_EQUAL(2, g_alloc_count); { - // Construct a NIL list - eterm term = list(nullptr); + // Construct a nil list + term et = list(nullptr); BOOST_CHECK_EQUAL(2, g_alloc_count); - auto term2 = term; + auto am = et; BOOST_CHECK_EQUAL(2, g_alloc_count); } BOOST_CHECK_EQUAL(2, g_alloc_count); From 3aff9edf34d09584330b1b04ff2575c6d31f70ad Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 23 Dec 2020 09:44:45 -0500 Subject: [PATCH 126/185] Fix endian conversion due to changes in boost --- CMakeLists.txt | 4 +++ Makefile | 6 ++-- bootstrap.mk => build-aux/bootstrap.mk | 1 - include/eixx/marshal/endian.hpp | 45 +++++++++++++++++++------- include/eixx/marshal/eterm.hxx | 13 +++----- 5 files changed, 44 insertions(+), 25 deletions(-) rename bootstrap.mk => build-aux/bootstrap.mk (98%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2ddece..aaabf7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,9 @@ # vim:ts=2:sw=2:et cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) + +# Overrides - must be placed before 'project' +set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_SOURCE_DIR}/build-aux/CMakeInit.txt") + project(eixx VERSION 1.4) #=============================================================================== diff --git a/Makefile b/Makefile index e2d1f61..ab9759b 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ distclean: @[ -n "$(DIR)" -a -d "$(DIR)" ] && echo "Removing $(DIR)" && rm -fr $(DIR) build inst || true bootstrap: - @$(MAKE) -f bootstrap.mk --no-print-directory $@ $(MAKEOVERRIDES) + @$(MAKE) -f build-aux/bootstrap.mk --no-print-directory $@ $(MAKEOVERRIDES) rebootstrap: .build/.bootstrap $(if $(build),$(filter-out build=%,$(shell cat $(REBOOSTR_FILE))) \ @@ -30,7 +30,7 @@ test: CTEST_OUTPUT_ON_FAILURE=TRUE $(generator) -C$(DIR) $(VERBOSE) -j$(shell nproc) $@ info ver: - @$(MAKE) -sf bootstrap.mk --no-print-directory $@ + @$(MAKE) -sf build-aux/bootstrap.mk --no-print-directory $@ vars: @cmake -H. -B$(DIR) -LA @@ -45,7 +45,7 @@ build/cache.mk: .DEFAULT: @if [ ! -f build/cache.mk ]; then \ - $(MAKE) -f bootstrap.mk --no-print-directory; \ + $(MAKE) -f build-aux/bootstrap.mk --no-print-directory; \ else \ $(generator) -C$(DIR) $(VERBOSE)\ $(if $(findstring $(generator),ninja),, --no-print-directory)\ diff --git a/bootstrap.mk b/build-aux/bootstrap.mk similarity index 98% rename from bootstrap.mk rename to build-aux/bootstrap.mk index dbc60d9..72bc0f7 100644 --- a/bootstrap.mk +++ b/build-aux/bootstrap.mk @@ -103,7 +103,6 @@ makecmd = $(envvars) cmake -H. -B$(DIR) \ $(if $(findstring $(generator),ninja),-GNinja,-G'Unix Makefiles') \ $(if $(findstring $(verbose),true on 1),-DCMAKE_VERBOSE_MAKEFILE=true) \ -DTOOLCHAIN=$(toolchain) \ - -DCMAKE_USER_MAKE_RULES_OVERRIDE=$(ROOT_DIR:%/=%)/build-aux/CMakeInit.txt \ -DCMAKE_INSTALL_PREFIX=$(prefix) \ -DCMAKE_BUILD_TYPE=$(build) $(makevars) diff --git a/include/eixx/marshal/endian.hpp b/include/eixx/marshal/endian.hpp index a5bc394..d692d4a 100644 --- a/include/eixx/marshal/endian.hpp +++ b/include/eixx/marshal/endian.hpp @@ -29,32 +29,53 @@ limitations under the License. #ifndef _EIXX_ENDIAN_HPP_ #define _EIXX_ENDIAN_HPP_ +#include #include +#if BOOST_VERSION >= 107100 +#include +#else #include +#endif namespace eixx { +namespace { +#if BOOST_VERSION >= 107100 + namespace bsd = boost::endian; +#elif BOOST_VERSION >= 104800 + namespace bsd = boost::spirit::detail; +#else + namespace bsd = boost::detail; +#endif +} + +template +inline void store_be(char* s, T n) { +#if BOOST_VERSION >= 107100 + bsd::endian_store(reinterpret_cast(s), n); +#else + bsd::store_big_endian(static_cast(s), n); +#endif +} + template inline void put_be(char*& s, T n) { - #if BOOST_VERSION >= 104900 - boost::spirit::detail::store_big_endian(s, n); - #else - boost::detail::store_big_endian(s, n); - #endif + store_be(s, n); s += sizeof(T); } template inline T cast_be(const char* s) { - #if BOOST_VERSION >= 104900 - return boost::spirit::detail::load_big_endian(s); - #else - return boost::detail::load_big_endian(s); - #endif +#if BOOST_VERSION >= 107100 + return bsd::endian_load + (reinterpret_cast(s)); +#else + return bsd::load_big_endian((const void*)s); +#endif } -template -inline void get_be(const char*& s, T& n) { +template +inline void get_be(const Ch*& s, T& n) { n = cast_be(s); s += sizeof(T); } diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index 43d8ed8..42df36a 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -26,6 +26,7 @@ limitations under the License. ***** END LICENSE BLOCK ***** */ #include +#include #include #include #include @@ -327,25 +328,19 @@ template void eterm::encode(char* a_buf, size_t size, size_t a_header_size, bool a_with_version) const { - #if BOOST_VERSION >= 104900 - namespace bd = boost::spirit::detail; - #else - namespace bd = boost::detail; - #endif - BOOST_ASSERT(size > 0); size_t msg_sz = size - a_header_size; switch (a_header_size) { case 0: break; case 1: - bd::store_big_endian(a_buf, msg_sz); + store_be(a_buf, static_cast(msg_sz)); break; case 2: - bd::store_big_endian(a_buf, msg_sz); + store_be(a_buf, static_cast(msg_sz)); break; case 4: - bd::store_big_endian(a_buf, msg_sz); + store_be(a_buf, static_cast(msg_sz)); break; default: { std::stringstream s; From 2846774c946f4824d800e4883d0793504a077070 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 23 Dec 2020 10:50:22 -0500 Subject: [PATCH 127/185] Fix package file --- eixx.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eixx.pc.in b/eixx.pc.in index 3346882..ee361c2 100644 --- a/eixx.pc.in +++ b/eixx.pc.in @@ -8,6 +8,6 @@ Name: @PROJECT_NAME@ Description: EIXX: C++ Interface to Erlang #Requires: boost_1_55_0 Version: @PROJECT_VERSION@ -Libs: -L${libdir} -L@Erlang_EI_LIBRARY_PATH@ -Wl,-rpath,${libdir} -leixx${libsuffix} -lei -lssl -lcrypto +Libs: -L${libdir} -L@Erlang_EI_LIBRARY_DIR@ -Wl,-rpath,${libdir} -leixx${libsuffix} -lei -lssl -lcrypto Cflags: -I${includedir} -I@Erlang_EI_INCLUDE_DIR@ From a3429f1120cae92822ad73d88338f742cc42a300 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 23 Dec 2020 22:06:54 -0500 Subject: [PATCH 128/185] Add pattern matcher constructor with 1 argument --- include/eixx/eterm.hpp | 3 ++ include/eixx/marshal/eterm_match.hpp | 44 ++++++++++++++++++++-------- test/test_eterm.cpp | 7 +++++ test/test_eterm_match.cpp | 25 ++++++++-------- 4 files changed, 55 insertions(+), 24 deletions(-) diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index 21a6497..123218c 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -32,6 +32,9 @@ limitations under the License. #include #include +#define EIXX_DECL_ATOM(Atom) static const eixx::atom am_##Atom(#Atom) +#define EIXX_DECL_ATOM_VAR(Name, Atom) static const eixx::atom Name(Atom) + namespace eixx { typedef marshal::eterm eterm; diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index dc2b63b..f9d2e7c 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -132,13 +132,25 @@ class eterm_pattern_matcher { return m_pattern_list.back(); } + const eterm_pattern_action& + push_back(const eterm& a_pattern) { + m_pattern_list.push_back(eterm_pattern_action(a_pattern)); + return m_pattern_list.back(); + } + /** * Add a pattern to the beginning of the list. * The pattern is assign to a smart pointer. */ const eterm_pattern_action& push_front(const eterm& a_pattern, pattern_functor_t a_fun, long a_opaque=0) { - m_pattern_list.push_back(eterm_pattern_action(a_pattern, a_fun, a_opaque)); + m_pattern_list.push_front(eterm_pattern_action(a_pattern, a_fun, a_opaque)); + return m_pattern_list.front(); + } + + const eterm_pattern_action& + push_front(const eterm& a_pattern) { + m_pattern_list.push_front(eterm_pattern_action(a_pattern)); return m_pattern_list.front(); } @@ -181,19 +193,16 @@ class eterm_pattern_matcher { * @param a_binding is an optional object containing * predefined variable bindings that will be passed * to every pattern. - * @return true if any one pattern matched the term. + * @return 0 if no terms matched, or the matched term's index + 1. */ - bool match(const eterm& a_term, - varbind* a_binding = NULL) const + int match(const eterm& a_term, + varbind* a_binding = NULL) const { - bool res = false; - for(auto it = m_pattern_list.begin(), end = m_pattern_list.end(); it != end; ++it) { - if (it->operator() (a_term, a_binding)) { - res = true; - break; - } - } - return res; + int i = 1; + for(auto it = m_pattern_list.begin(), end = m_pattern_list.end(); it != end; ++it, ++i) + if ((*it)(a_term, a_binding)) + return i; + return 0; } private: list_t m_pattern_list; @@ -212,6 +221,17 @@ class eterm_pattern_action { pattern_functor_t m_fun; long m_opaque; public: + /** + * Create a new pattern match action without a functor. + * @param a_pattern pattern to match + */ + explicit eterm_pattern_action(const eterm& a_pattern) + : m_pattern(a_pattern), m_opaque(0) + { + auto fun = [](auto& pattern, auto& vars, long opaque) { return true; }; + m_fun = fun; + } + /** * Create a new pattern match functor. * @param a_pattern pattern to match diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index ab394e9..79709fb 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -39,6 +39,13 @@ BOOST_AUTO_TEST_CASE( test_atomable ) BOOST_AUTO_TEST_CASE( test_atom ) { + { + EIXX_DECL_ATOM(temp); + BOOST_REQUIRE_EQUAL("temp", am_temp); + + EIXX_DECL_ATOM_VAR(am_temp2, "temp2"); + BOOST_REQUIRE_EQUAL("temp2", am_temp2); + } { atom a(""); BOOST_REQUIRE_EQUAL(0, a.index()); diff --git a/test/test_eterm_match.cpp b/test/test_eterm_match.cpp index 99db984..6e911b9 100644 --- a/test/test_eterm_match.cpp +++ b/test/test_eterm_match.cpp @@ -106,10 +106,12 @@ namespace { BOOST_REQUIRE(a_varbind.find("X") != NULL); BOOST_REQUIRE_EQUAL(TUPLE, a_varbind.find("X")->type()); break; + case 5: + match[4]++; + break; default: throw "Invalid opaque value!"; } - return true; } return true; } @@ -144,9 +146,10 @@ BOOST_AUTO_TEST_CASE( test_match2 ) etm.push_back(eterm::format("{xxx, [_, _, {c, N}], \"abc\", X}"), std::bind(&cb_t::operator(), &cb, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), 4); + etm.push_back(eterm::format("{login, I::int()}")); // Make sure we registered 4 pattern above. - BOOST_REQUIRE_EQUAL(4u, etm.size()); + BOOST_REQUIRE_EQUAL(5u, etm.size()); static const eterm t0 = atom("test"); eterm f0 = eterm::format("test"); @@ -157,17 +160,18 @@ BOOST_AUTO_TEST_CASE( test_match2 ) auto f1 = eterm::format("{test, 1, 123}"); auto m1 = etm.match(f1); BOOST_REQUIRE(m1); // N = 1 - BOOST_REQUIRE(etm.match(eterm::format("{test, 1, 234}"))); // N = 1 + BOOST_REQUIRE_EQUAL(1, etm.match(eterm::format("{test, 1, 234}"))); // N = 1 - BOOST_REQUIRE(etm.match(eterm::format("{ok, 2, 3, 4}"))); // N = 2 - BOOST_REQUIRE(!etm.match(eterm::format("{ok, 2}"))); + BOOST_REQUIRE_EQUAL(2, etm.match(eterm::format("{ok, 2, 3, 4}"))); // N = 2 + BOOST_REQUIRE_EQUAL(0, etm.match(eterm::format("{ok, 2}"))); - BOOST_REQUIRE(etm.match(eterm::format("{error, 3, not_found}"))); // N = 3 + BOOST_REQUIRE_EQUAL(3, etm.match(eterm::format("{error, 3, not_found}"))); // N = 3 - BOOST_REQUIRE(etm.match( + BOOST_REQUIRE_EQUAL(4, etm.match( eterm::format("{xxx, [{a, 1}, {b, 2}, {c, 4}], \"abc\", {5,6,7}}"))); // N = 4 - BOOST_REQUIRE(!etm.match( + BOOST_REQUIRE_EQUAL(0, etm.match( eterm::format("{xxx, [1, 2, 3, {c, 4}], \"abc\", 5}"))); + BOOST_REQUIRE_EQUAL(5, etm.match(eterm::format("{login, 1}"))); // Verify number of successful matches for each pattern. BOOST_REQUIRE_EQUAL(2, cb.match[0]); @@ -175,13 +179,10 @@ BOOST_AUTO_TEST_CASE( test_match2 ) BOOST_REQUIRE_EQUAL(1, cb.match[2]); BOOST_REQUIRE_EQUAL(1, cb.match[3]); - // Make sure we registered 4 pattern above. - BOOST_REQUIRE_EQUAL(4u, etm.size()); - // Test pattern deletion. etm.erase(action); // Make sure we registered 4 pattern above. - BOOST_REQUIRE_EQUAL(3u, etm.size()); + BOOST_REQUIRE_EQUAL(4u, etm.size()); } BOOST_AUTO_TEST_CASE( test_match3 ) From f33065e5d2a6d6d2c550fdb64c94f0af2b52ef1b Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 28 Dec 2020 10:32:25 -0500 Subject: [PATCH 129/185] Add test case --- include/eixx/marshal/varbind.hpp | 12 ++++++++++++ test/test_eterm.cpp | 13 ++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/include/eixx/marshal/varbind.hpp b/include/eixx/marshal/varbind.hpp index a6c4503..816eceb 100644 --- a/include/eixx/marshal/varbind.hpp +++ b/include/eixx/marshal/varbind.hpp @@ -149,6 +149,18 @@ class varbind { return p; } + const eterm& get(const char* a_var_name) const { + auto res = (*this)[a_var_name]; + assert (res); + return *res; + } + + const eterm& get(atom a_var_name) const { + auto res = (*this)[a_var_name]; + assert (res); + return *res; + } + /** * Merge all data in a variable binding with data in this * variable binding. diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 79709fb..02088ba 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -661,20 +661,23 @@ BOOST_AUTO_TEST_CASE( test_varbind ) allocator_t alloc; varbind binding1; - binding1.bind(atom("Name"), 20.0); + EIXX_DECL_ATOM(Name); + binding1.bind(am_Name, 20.0); binding1.bind(atom("Long"), 123); varbind binding2; - binding2.bind(atom("Name"), atom("test")); + binding2.bind(am_Name, atom("test")); binding2.bind(atom("Other"), "vasya"); binding1.merge(binding2); BOOST_REQUIRE_EQUAL(3ul, binding1.count()); + BOOST_REQUIRE(binding1[am_Name]); + BOOST_REQUIRE_EQUAL(eterm(20.0), binding1.get(am_Name)); #if __cplusplus >= 201103L - atom am_a("A"); - atom am_b("B"); - atom am_c("C"); + EIXX_DECL_ATOM_VAR(am_a, "A"); + EIXX_DECL_ATOM_VAR(am_b, "B"); + EIXX_DECL_ATOM_VAR(am_c, "C"); varbind binding3{ {am_a, 10}, {am_b, 200.0}, {"C", "abc"} }; BOOST_CHECK_EQUAL(3u, binding3.count()); From 8d9182fed93d3f8cb4d750de209db1de2b410c38 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 11 Jan 2021 17:07:03 -0500 Subject: [PATCH 130/185] Add check for existing atom --- include/eixx/eterm_exception.hpp | 15 ++++++++----- include/eixx/marshal/atom.hpp | 22 +++++++++++++++++++ include/eixx/marshal/eterm.hpp | 33 ++++++++++++++++++++++++++-- include/eixx/util/atom_table.hpp | 37 +++++++++++++++++++++++--------- include/eixx/util/sync.hpp | 29 ++++++++++++++++++------- test/test_eterm.cpp | 7 ++++++ 6 files changed, 118 insertions(+), 25 deletions(-) diff --git a/include/eixx/eterm_exception.hpp b/include/eixx/eterm_exception.hpp index 6bd9b07..d0efc55 100644 --- a/include/eixx/eterm_exception.hpp +++ b/include/eixx/eterm_exception.hpp @@ -59,11 +59,16 @@ class eterm_exception: public std::exception { std::string m_msg; }; -/** - * Exception for invalid terms - */ -class err_invalid_term: public eterm_exception { -public: +/// Exception for invalid atoms +struct err_atom_not_found: public eterm_exception { + err_atom_not_found(std::string const& atom) + : eterm_exception("Atom '" + atom + "' not found") + {} + err_atom_not_found() : eterm_exception("Atom not found") {} +}; + +/// Exception for invalid terms +struct err_invalid_term: public eterm_exception { err_invalid_term(const std::string &msg) : eterm_exception(msg) {} }; diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 55bd2aa..924dc19 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -101,12 +101,34 @@ class atom : m_index(atom_table().lookup(s)) {} + /// @copydoc atom::atom + /// @param existing if true, check that the atom already exists, otherwise throw + /// err_atom_not_found + atom(const char* s, bool existing) + : atom(std::string(s), existing) + {} + atom(const std::string& s, bool existing) + { + if (!existing) { + m_index = atom_table().lookup(s); + return; + } + bool found; + std::tie(m_index, found) = atom_table().try_lookup(s); + if (!found) + throw err_atom_not_found(s); + } + /// @copydoc atom::atom template explicit atom(const string& s) : m_index(atom_table().lookup(std::string(s.c_str(), s.size()))) {} + /// @copydoc atom::atom + atom(const char* s, int n) : atom(s, size_t(n)) {} + /// @copydoc atom::atom + atom(const char* s, long n) : atom(s, size_t(n)) {} /// @copydoc atom::atom atom(const char* s, size_t n) : m_index(atom_table().lookup(std::string(s, n))) diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index fd9fb46..5368cac 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -431,6 +431,32 @@ class eterm { // Separated into a separate function without default args for ease of gdb debugging std::string to_string() const { return to_string(std::string::npos, NULL); } + // Return the term as a value of given type. + // NOTE: only integer | double | bool | string types are supported + template + typename std::enable_if::value, bool>::type + to_type() const { return to_double(); } + + template + typename std::enable_if::value, bool>::type + to_type() const { return to_bool(); } + + template + typename std::enable_if::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value + , bool>::type + to_type() const { return to_long(); } + + template + typename std::enable_if::value, bool>::type + to_type() const { return to_str(); } + // Convert a term to its underlying type. Will throw an exception // when the underlying type doesn't correspond to the requested operation. @@ -444,8 +470,11 @@ class eterm { check(STRING); return vt.s; } const std::string as_str() const { - if (m_type==LIST && vt.l.empty()) return std::string(); - check(STRING); return vt.s.to_str(); + static const std::string s_null; + return m_type==LIST && vt.l.empty() + ? s_null + : m_type==STRING + ? vt.s.to_str() : to_string(); } const binary& to_binary() const { check(BINARY); return vt.bin; } const epid& to_pid() const { check(PID); return vt.pid; } diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 70a1605..0cc8f4e 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -104,6 +104,23 @@ namespace util { return m_atoms[n]; } + /// Try to lookup an atom in the atom table + /// @return {-1, false} if the atom is not found, {-2, false} if the atom is invalid, + /// or {AtomIndex, true} if existing atom is found. + std::pair try_lookup(const char* a_name, size_t n) { return try_lookup(String(a_name, n)); } + std::pair try_lookup(const char* a_name) { return try_lookup(String(a_name)); } + std::pair try_lookup(const String& a_name) + { + if (a_name.size() == 0) + return std::make_pair(0, true); + if (a_name.size() > MAXATOMLEN) + return std::make_pair(-2, false); + size_t bucket = m_index.bucket(a_name.c_str()); + int n = find_value(bucket, a_name.c_str()); + return n >= 0 ? std::make_pair(n, true) + : std::make_pair(-1, false); + } + /// Lookup an atom in the atom table by name. If the atom is not /// present in the atom table - add it. Return the index of the /// atom in the atom table. @@ -113,19 +130,19 @@ namespace util { int lookup(const char* a_name) { return lookup(String(a_name)); } int lookup(const String& a_name) { - if (a_name.size() == 0) - return 0; - if (a_name.size() > MAXATOMLEN) - throw err_bad_argument("Atom size is too long!"); - size_t bucket = m_index.bucket(a_name.c_str()); - int n = find_value(bucket, a_name.c_str()); - if (n >= 0) + auto [n, found] = try_lookup(a_name); + if (found) return n; + if (n == -2) + throw err_bad_argument("Atom size is too long!"); lock_guard guard(m_lock); - n = find_value(bucket, a_name.c_str()); - if (n >= 0) - return n; + if constexpr (!std::is_same::value) { + size_t bucket = m_index.bucket(a_name.c_str()); + n = find_value(bucket, a_name.c_str()); + if (n >= 0) + return n; + } n = m_atoms.size(); if ((size_t)(n+1) == m_atoms.capacity()) diff --git a/include/eixx/util/sync.hpp b/include/eixx/util/sync.hpp index bcbd260..d058fd4 100644 --- a/include/eixx/util/sync.hpp +++ b/include/eixx/util/sync.hpp @@ -31,25 +31,38 @@ limitations under the License. namespace eixx { namespace detail { -#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L -typedef std::mutex mutex; -typedef std::recursive_mutex recursive_mutex; -template struct lock_guard: public std::lock_guard { - lock_guard(Mutex& a_m) : std::lock_guard(a_m) {} +struct null_mutex { + void lock() {} + void unlock() noexcept {} + bool try_lock() { return true; } }; -#else + +#if __cplusplus < 201103L typedef boost::mutex mutex; typedef boost::recursive_mutex recursive_mutex; // Note that definition of boost::lock_guard is missing mutex_type compared // to the definition of std::lock_guard. template struct lock_guard: public boost::lock_guard { - typedef boost::mutex mutex_type; + typedef Mutex mutex_type; lock_guard(Mutex& a_m) : boost::lock_guard(a_m) {} }; +#else +template struct lock_guard: public std::lock_guard { + lock_guard(Mutex& a_m) : std::lock_guard(a_m) {} +}; + #ifdef EIXX_NULL_MUTEX + typedef null_mutex mutex; + typedef null_mutex recursive_mutex; + template struct lock_guard: public std::lock_guard { + lock_guard(Mutex& a_m) : std::lock_guard(a_m) {} + }; + #else + typedef std::mutex mutex; + typedef std::recursive_mutex recursive_mutex; + #endif #endif } // namespace detail } // namespace eixx #endif // _EIXX_SYNC_HPP_ - diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 02088ba..2c51fca 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -46,6 +46,13 @@ BOOST_AUTO_TEST_CASE( test_atom ) EIXX_DECL_ATOM_VAR(am_temp2, "temp2"); BOOST_REQUIRE_EQUAL("temp2", am_temp2); } + { + auto [n, found] = util::atom_table().try_lookup("temp3"); + BOOST_REQUIRE(found == false); + BOOST_CHECK_THROW(atom("temp3", true), err_atom_not_found); + auto a = atom("temp3", false); + BOOST_CHECK_EQUAL("temp3", a); + } { atom a(""); BOOST_REQUIRE_EQUAL(0, a.index()); From 9f305ff38a5a0b2e5afdc5b31a24ef96bf9b20ad Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 11 Jan 2021 17:35:10 -0500 Subject: [PATCH 131/185] Add atom::create --- include/eixx/marshal/atom.hpp | 21 ++++++++++++++++----- include/eixx/util/atom_table.hpp | 27 ++++++++++++--------------- test/test_eterm.cpp | 10 ++++++++-- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 924dc19..43a20dc 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -67,6 +67,7 @@ class atom { int m_index; + atom(int idx) : m_index(idx) { assert(idx >= 0); } public: inline static util::atom_table& atom_table() { static util::atom_table s_atom_table; @@ -98,8 +99,19 @@ class atom /// @copydoc atom::atom explicit atom(const std::string& s) - : m_index(atom_table().lookup(s)) - {} + : m_index(atom_table().lookup(s)) {} + + /// Try to create an atom without throwing exceptions + /// NOTE: if the atom name is invalid or it doesn't exist and \a existing + /// is true, then an empty atom is returned. + static atom create(const std::string& s, bool existing) { + auto idx = atom_table().try_lookup(s); + return idx > 0 && existing ? atom(idx) : atom(); + } + /// @copydoc atom::create + static atom create(const char* s, bool existing) { + return create(std::string(s), existing); + } /// @copydoc atom::atom /// @param existing if true, check that the atom already exists, otherwise throw @@ -113,9 +125,8 @@ class atom m_index = atom_table().lookup(s); return; } - bool found; - std::tie(m_index, found) = atom_table().try_lookup(s); - if (!found) + m_index = atom_table().try_lookup(s); + if (m_index <= 0) throw err_atom_not_found(s); } diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 0cc8f4e..6a5845e 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -105,20 +105,19 @@ namespace util { } /// Try to lookup an atom in the atom table - /// @return {-1, false} if the atom is not found, {-2, false} if the atom is invalid, - /// or {AtomIndex, true} if existing atom is found. - std::pair try_lookup(const char* a_name, size_t n) { return try_lookup(String(a_name, n)); } - std::pair try_lookup(const char* a_name) { return try_lookup(String(a_name)); } - std::pair try_lookup(const String& a_name) + /// @return -1 if the atom by name is not found, -2 if the atom is invalid, + /// or a value >= 0, if an existing atom is found. + int try_lookup(const char* a_name, size_t n) { return try_lookup(String(a_name, n)); } + int try_lookup(const char* a_name) { return try_lookup(String(a_name)); } + int try_lookup(const String& a_name) { if (a_name.size() == 0) - return std::make_pair(0, true); + return 0; if (a_name.size() > MAXATOMLEN) - return std::make_pair(-2, false); + return -2; size_t bucket = m_index.bucket(a_name.c_str()); - int n = find_value(bucket, a_name.c_str()); - return n >= 0 ? std::make_pair(n, true) - : std::make_pair(-1, false); + int n = find_value(bucket, a_name.c_str()); + return n > 0 ? n : -1; } /// Lookup an atom in the atom table by name. If the atom is not @@ -130,11 +129,9 @@ namespace util { int lookup(const char* a_name) { return lookup(String(a_name)); } int lookup(const String& a_name) { - auto [n, found] = try_lookup(a_name); - if (found) - return n; - if (n == -2) - throw err_bad_argument("Atom size is too long!"); + auto n = try_lookup(a_name); + if (n >= 0) return n; + if (n == -2) throw err_bad_argument("Atom size is too long!"); lock_guard guard(m_lock); if constexpr (!std::is_same::value) { diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 2c51fca..f986dae 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -47,8 +47,14 @@ BOOST_AUTO_TEST_CASE( test_atom ) BOOST_REQUIRE_EQUAL("temp2", am_temp2); } { - auto [n, found] = util::atom_table().try_lookup("temp3"); - BOOST_REQUIRE(found == false); + auto n = util::atom_table().try_lookup("temp3"); + BOOST_REQUIRE_EQUAL(-1, n); + auto s = std::string(MAXATOMLEN+1, 'X'); + n = util::atom_table().try_lookup(s); + BOOST_REQUIRE_EQUAL(-2, n); + n = util::atom_table().try_lookup(""); + BOOST_REQUIRE_EQUAL(0, n); + BOOST_CHECK_THROW(atom("temp3", true), err_atom_not_found); auto a = atom("temp3", false); BOOST_CHECK_EQUAL("temp3", a); From b7c6345d26f9528d01e333b3ed15927ca8cf1ea3 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 11 Jan 2021 18:10:40 -0500 Subject: [PATCH 132/185] Update boost --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 913683d..b464acd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ matrix: - gcc-9 - g++-9 #- boost-latest - - boost1.70 + - boost1.74 #- cmake #- cmake-data - libxslt1.1 From 39f6099640698f373af44f09143eb4029029c391 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 11 Jan 2021 18:41:03 -0500 Subject: [PATCH 133/185] Update GCC --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b464acd..f1679ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,8 @@ matrix: - sourceline: 'ppa:mhier/libboost-latest' - sourceline: 'ppa:ubuntu-toolchain-r/test' packages: - - gcc-9 - - g++-9 + - gcc-10 + - g++-10 #- boost-latest - boost1.74 #- cmake @@ -24,7 +24,7 @@ matrix: - python-lxml - doxygen env: - - MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" + - MATRIX_EVAL="CC=gcc-10 && CXX=g++-10" before_install: - eval "${MATRIX_EVAL}" From 2b3b4506e3396bc61dea71cc46ad716a46ce9920 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 11 Jan 2021 18:53:23 -0500 Subject: [PATCH 134/185] Fix errors --- include/eixx/marshal/eterm.hpp | 14 +++++++------- test/test_eterm.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 5368cac..3d6e277 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -434,12 +434,12 @@ class eterm { // Return the term as a value of given type. // NOTE: only integer | double | bool | string types are supported template - typename std::enable_if::value, bool>::type - to_type() const { return to_double(); } + typename std::enable_if::value, double>::type + get() const { return to_double(); } template typename std::enable_if::value, bool>::type - to_type() const { return to_bool(); } + get() const { return to_bool(); } template typename std::enable_if::value || @@ -450,12 +450,12 @@ class eterm { std::is_same::value || std::is_same::value || std::is_same::value - , bool>::type - to_type() const { return to_long(); } + , T>::type + get() const { return T(to_long()); } template - typename std::enable_if::value, bool>::type - to_type() const { return to_str(); } + typename std::enable_if::value, std::string>::type + get() const { return to_str().to_str(); } // Convert a term to its underlying type. Will throw an exception // when the underlying type doesn't correspond to the requested operation. diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index f986dae..a175cdc 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -26,6 +26,35 @@ limitations under the License. using namespace eixx; +BOOST_AUTO_TEST_CASE( test_type ) +{ + { + eterm t(10); + BOOST_REQUIRE_EQUAL(10, t.get()); + BOOST_REQUIRE_EQUAL(10, t.get()); + BOOST_REQUIRE_EQUAL(10, t.get()); + BOOST_REQUIRE_EQUAL(10, t.get()); + BOOST_REQUIRE_EQUAL(10, t.get()); + BOOST_REQUIRE_EQUAL(10, t.get()); + BOOST_CHECK_THROW(t.get(), err_wrong_type); + } + { + eterm t(10.0); + BOOST_REQUIRE_EQUAL(10.0, t.get()); + BOOST_CHECK_THROW(t.get(), err_wrong_type); + } + { + eterm t(true); + BOOST_REQUIRE_EQUAL(true, t.get()); + BOOST_CHECK_THROW(t.get(), err_wrong_type); + } + { + eterm t("ABC"); + BOOST_REQUIRE_EQUAL("ABC", t.get()); + BOOST_CHECK_THROW(t.get(), err_wrong_type); + } +} + BOOST_AUTO_TEST_CASE( test_atomable ) { util::atom_table t(10); From 6c77f4d90c7d7210972537b87875c82003c80d37 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 12 Jan 2021 14:02:42 -0500 Subject: [PATCH 135/185] Fix travis build issue --- .travis.yml | 4 ++-- include/eixx/util/atom_table.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f1679ff..1adcb0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,8 @@ matrix: - sourceline: 'ppa:mhier/libboost-latest' - sourceline: 'ppa:ubuntu-toolchain-r/test' packages: - - gcc-10 - - g++-10 + - gcc-9 + - g++-9 #- boost-latest - boost1.74 #- cmake diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 6a5845e..774c3fc 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -134,7 +134,7 @@ namespace util { if (n == -2) throw err_bad_argument("Atom size is too long!"); lock_guard guard(m_lock); - if constexpr (!std::is_same::value) { + if (!std::is_same::value) { size_t bucket = m_index.bucket(a_name.c_str()); n = find_value(bucket, a_name.c_str()); if (n >= 0) From c42f1eaf6d37bced8e52a33f23cd598ab118c0c5 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 12 Jan 2021 14:47:17 -0500 Subject: [PATCH 136/185] Fix travis build --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1adcb0e..63e74c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,13 +18,11 @@ matrix: - g++-9 #- boost-latest - boost1.74 - #- cmake - #- cmake-data - libxslt1.1 - python-lxml - doxygen env: - - MATRIX_EVAL="CC=gcc-10 && CXX=g++-10" + - MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" before_install: - eval "${MATRIX_EVAL}" From 832e0c36eeeb2338a3bd7601c3def65c44889fa7 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 25 Jan 2021 14:30:05 -0500 Subject: [PATCH 137/185] Add declaration of atom macro --- include/eixx/eterm.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index 123218c..e075500 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -33,6 +33,7 @@ limitations under the License. #include #define EIXX_DECL_ATOM(Atom) static const eixx::atom am_##Atom(#Atom) +#define EIXX_DECL_ATOM_VAL(Atom, Val) static const eixx::atom am_##Atom(Val) #define EIXX_DECL_ATOM_VAR(Name, Atom) static const eixx::atom Name(Atom) namespace eixx { From 809c4db940d31c3351cfa2490b369a93a7737ce2 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 25 Jan 2021 14:31:47 -0500 Subject: [PATCH 138/185] Add declaration of atom macro --- include/eixx/eterm.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index e075500..a59b0a8 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -33,7 +33,7 @@ limitations under the License. #include #define EIXX_DECL_ATOM(Atom) static const eixx::atom am_##Atom(#Atom) -#define EIXX_DECL_ATOM_VAL(Atom, Val) static const eixx::atom am_##Atom(Val) +#define EIXX_DECL_ATOM_VAL(Atom, Val) static const eixx::atom am_##Atom(#Val) #define EIXX_DECL_ATOM_VAR(Name, Atom) static const eixx::atom Name(Atom) namespace eixx { From d01bdb2d31d28dbda46ba96f03b595f3408bedab Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 25 Jan 2021 14:32:18 -0500 Subject: [PATCH 139/185] Add declaration of atom macro --- include/eixx/eterm.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index a59b0a8..e075500 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -33,7 +33,7 @@ limitations under the License. #include #define EIXX_DECL_ATOM(Atom) static const eixx::atom am_##Atom(#Atom) -#define EIXX_DECL_ATOM_VAL(Atom, Val) static const eixx::atom am_##Atom(#Val) +#define EIXX_DECL_ATOM_VAL(Atom, Val) static const eixx::atom am_##Atom(Val) #define EIXX_DECL_ATOM_VAR(Name, Atom) static const eixx::atom Name(Atom) namespace eixx { From 955910061b9c40c1f8da25e15b1f3e46c8af4748 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Feb 2021 19:48:24 -0500 Subject: [PATCH 140/185] Minor fixes --- build-aux/CMakeInit.txt | 3 ++- include/eixx/eterm_exception.hpp | 7 ++++--- include/eixx/marshal/eterm.hxx | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/build-aux/CMakeInit.txt b/build-aux/CMakeInit.txt index 1b4a651..500fd78 100644 --- a/build-aux/CMakeInit.txt +++ b/build-aux/CMakeInit.txt @@ -4,7 +4,8 @@ SET (CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") SET (CMAKE_C_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g") -SET (CMAKE_CXX_FLAGS_INIT "-Wall -std=c++17 -march=native -Wno-deprecated -Wno-deprecated-declarations") +SET (CMAKE_CXX_FLAGS_INIT "-Wall -march=native -Wno-deprecated -Wno-deprecated-declarations") +SET (CMAKE_CXX_STANDARD 17) SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g -O0") SET (CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") SET (CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") diff --git a/include/eixx/eterm_exception.hpp b/include/eixx/eterm_exception.hpp index d0efc55..bddefbd 100644 --- a/include/eixx/eterm_exception.hpp +++ b/include/eixx/eterm_exception.hpp @@ -43,10 +43,11 @@ class eterm_exception: public std::exception { eterm_exception() {} eterm_exception(const std::string& msg): m_msg(msg) {} - template - eterm_exception(const std::string& msg, Arg a) { + template + eterm_exception(const std::string& msg, Arg&&... a) { std::ostringstream str; - str << msg << ": " << a; + str << msg << ": "; + (str << ... << a); // Fold expression m_msg = str.str(); } diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index 42df36a..c19a898 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -118,6 +118,7 @@ const char* eterm::type_string() const { case LIST: return "list"; case MAP: return "map"; case TRACE: return "trace"; + default: throw err_invalid_term("Term type not supported: ", int(m_type)); } static_assert(MAX_ETERM_TYPE == 14, "Invalid number of terms"); } From 9d7359b224c8f65c96214b97d13f494a5ddfa7fe Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Feb 2021 19:59:08 -0500 Subject: [PATCH 141/185] Fix exception --- include/eixx/marshal/eterm.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index c19a898..8872f99 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -118,7 +118,7 @@ const char* eterm::type_string() const { case LIST: return "list"; case MAP: return "map"; case TRACE: return "trace"; - default: throw err_invalid_term("Term type not supported: ", int(m_type)); + default: throw eterm_exception("Term type not supported: ", int(m_type)); } static_assert(MAX_ETERM_TYPE == 14, "Invalid number of terms"); } From 465cadc306e570267e8829dcda61977b163e7ad5 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Feb 2021 20:26:17 -0500 Subject: [PATCH 142/185] Build Travis with gcc-10 --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 63e74c9..13e52f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,15 +14,15 @@ matrix: - sourceline: 'ppa:mhier/libboost-latest' - sourceline: 'ppa:ubuntu-toolchain-r/test' packages: - - gcc-9 - - g++-9 + - gcc-10 + - g++-10 #- boost-latest - boost1.74 - libxslt1.1 - python-lxml - doxygen env: - - MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" + - MATRIX_EVAL="CC=gcc-10 && CXX=g++-10" before_install: - eval "${MATRIX_EVAL}" From 62d5326c0ba5b8df7a49c6f836b55101f40cab2a Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Feb 2021 20:34:31 -0500 Subject: [PATCH 143/185] Add gcc repositories --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 13e52f3..398c200 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ matrix: sources: - sourceline: 'ppa:mhier/libboost-latest' - sourceline: 'ppa:ubuntu-toolchain-r/test' + - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: - gcc-10 - g++-10 From 1213d02e5c73435f769beb7e5cf644fd8aa25f40 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 16 Feb 2021 20:39:35 -0500 Subject: [PATCH 144/185] Fix Travis --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 398c200..c9b2969 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,9 +12,7 @@ matrix: update: true sources: - sourceline: 'ppa:mhier/libboost-latest' - - sourceline: 'ppa:ubuntu-toolchain-r/test' - - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' - key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' + - ubuntu-toolchain-r-test packages: - gcc-10 - g++-10 From f357e37e063a42e151ebb980683f70134e9c5d5f Mon Sep 17 00:00:00 2001 From: Dmitriy Kargapolov Date: Sat, 20 Mar 2021 10:02:38 -0400 Subject: [PATCH 145/185] Do not rely on past guess about encoding size This at least didn't work with Erlang/OTP 23, tested with erlang-jinterface-23.2.3-1.el7.x86_64 from Erlang Solutions, where boolean encoded size was 1 byte less then old code expected --- include/eixx/marshal/visit_encode_size.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/eixx/marshal/visit_encode_size.hpp b/include/eixx/marshal/visit_encode_size.hpp index 2f139d9..8150689 100644 --- a/include/eixx/marshal/visit_encode_size.hpp +++ b/include/eixx/marshal/visit_encode_size.hpp @@ -38,8 +38,8 @@ template struct visit_eterm_encode_size_calc : public static_visitor, size_t> { - size_t operator()(bool a) const { return 3 + (a ? 4 : 5); } - size_t operator()(double a) const { return 9; } + size_t operator()(bool a) const { int n = 0; ei_encode_boolean(NULL, &n, a); return n; } + size_t operator()(double a) const { int n = 0; ei_encode_double(NULL, &n, a); return n; } size_t operator()(long a) const { int n = 0; ei_encode_longlong(NULL, &n, a); return n; } template From 32a94acc680b7d72b238352dc0f6cef3dc483765 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 22 Mar 2021 21:57:44 -0400 Subject: [PATCH 146/185] Add g++-10 source repos --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index c9b2969..7fd4125 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,10 @@ matrix: apt: update: true sources: + - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - sourceline: 'ppa:mhier/libboost-latest' + #- sourceline: 'ppa:ubuntu-toolchain-r/test' - ubuntu-toolchain-r-test packages: - gcc-10 From f071291f816a237d44162a0879ef65a6410967f6 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 22 Mar 2021 22:14:26 -0400 Subject: [PATCH 147/185] Add g++-10 source repos --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7fd4125..80c732a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,12 +7,11 @@ otp_release: matrix: include: - os: linux + dist: bionic # Required for gcc-10 addons: apt: update: true sources: - - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' - key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - sourceline: 'ppa:mhier/libboost-latest' #- sourceline: 'ppa:ubuntu-toolchain-r/test' - ubuntu-toolchain-r-test From c5b3d8f6580f054070b93147abde762577be3998 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 22 Mar 2021 23:05:54 -0400 Subject: [PATCH 148/185] Revert back the encoding of bool and double to preserve inlining --- include/eixx/marshal/visit_encode_size.hpp | 4 ++-- test/test_eterm.cpp | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/eixx/marshal/visit_encode_size.hpp b/include/eixx/marshal/visit_encode_size.hpp index 8150689..7458b47 100644 --- a/include/eixx/marshal/visit_encode_size.hpp +++ b/include/eixx/marshal/visit_encode_size.hpp @@ -38,8 +38,8 @@ template struct visit_eterm_encode_size_calc : public static_visitor, size_t> { - size_t operator()(bool a) const { int n = 0; ei_encode_boolean(NULL, &n, a); return n; } - size_t operator()(double a) const { int n = 0; ei_encode_double(NULL, &n, a); return n; } + size_t operator()(bool a) const { return 2 + (a ? 4 : 5); } + size_t operator()(double a) const { return 9; } size_t operator()(long a) const { int n = 0; ei_encode_longlong(NULL, &n, a); return n; } template diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index a175cdc..6e5c158 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -23,6 +23,7 @@ limitations under the License. #include "test_alloc.hpp" #include #include +#include using namespace eixx; @@ -124,9 +125,26 @@ BOOST_AUTO_TEST_CASE( test_bool ) { allocator_t alloc; { + int n; eterm et(true); BOOST_REQUIRE(et.initialized()); BOOST_REQUIRE_EQUAL(BOOL, et.type()); + // Since the encode_size() functions for bool and double don't call + // ei's implementation but have hard-coded values inlined for efficiency, + // test that our assumption of the return matches the return of the + // corresponding ei's implementation: + BOOST_REQUIRE_EQUAL(6, marshal::visit_eterm_encode_size_calc()(true)); + BOOST_REQUIRE_EQUAL(7, marshal::visit_eterm_encode_size_calc()(false)); + BOOST_REQUIRE_EQUAL(9, marshal::visit_eterm_encode_size_calc()(0.0)); + n = 0; + BOOST_REQUIRE_EQUAL(0, ei_encode_boolean(NULL, &n, true)); + BOOST_CHECK_EQUAL(n, marshal::visit_eterm_encode_size_calc()(true)); + n = 0; + BOOST_REQUIRE_EQUAL(0, ei_encode_boolean(NULL, &n, false)); + BOOST_CHECK_EQUAL(n, marshal::visit_eterm_encode_size_calc()(false)); + n = 0; + BOOST_REQUIRE_EQUAL(0, ei_encode_double(NULL, &n, 0.0)); + BOOST_CHECK_EQUAL(n, marshal::visit_eterm_encode_size_calc()(0.0)); } { From a4757c44ef3c8259107ca4ccae3b37de57df6b06 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 3 May 2021 21:43:20 -0400 Subject: [PATCH 149/185] Make compilation C++20 compliant --- build-aux/CMakeInit.txt | 2 +- include/eixx/marshal/alloc_base.hpp | 16 ++++++++-------- include/eixx/marshal/eterm_format.hxx | 10 +++++++--- include/eixx/marshal/eterm_match.hpp | 4 ++-- include/eixx/marshal/map.hpp | 2 +- include/eixx/marshal/varbind.hpp | 3 ++- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/build-aux/CMakeInit.txt b/build-aux/CMakeInit.txt index 500fd78..3c5eac5 100644 --- a/build-aux/CMakeInit.txt +++ b/build-aux/CMakeInit.txt @@ -5,7 +5,7 @@ SET (CMAKE_C_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g") SET (CMAKE_CXX_FLAGS_INIT "-Wall -march=native -Wno-deprecated -Wno-deprecated-declarations") -SET (CMAKE_CXX_STANDARD 17) +SET (CMAKE_CXX_STANDARD 20) SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g -O0") SET (CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") SET (CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") diff --git a/include/eixx/marshal/alloc_base.hpp b/include/eixx/marshal/alloc_base.hpp index 41b99d5..bf11acc 100644 --- a/include/eixx/marshal/alloc_base.hpp +++ b/include/eixx/marshal/alloc_base.hpp @@ -39,7 +39,7 @@ namespace marshal { template struct alloc_base_impl { - typedef typename Alloc::template rebind::other T_alloc_type; + using T_alloc_type = typename std::allocator_traits::template rebind_alloc; struct alloc_impl: public T_alloc_type { alloc_impl() : T_alloc_type() {} @@ -53,11 +53,11 @@ namespace marshal { /// empty base class optimization. template class alloc_base : private alloc_base_impl::alloc_impl { - typedef alloc_base_impl impl_t; - typedef typename impl_t::alloc_impl base_t; + using impl_t = alloc_base_impl; + using base_t = typename impl_t::alloc_impl; public: - typedef Alloc allocator_type; - typedef typename impl_t::T_alloc_type T_alloc_type; + using allocator_type = Alloc; + using T_alloc_type = typename impl_t::T_alloc_type; alloc_base() {} alloc_base(const Alloc& alloc) : base_t(alloc) {} @@ -75,10 +75,10 @@ namespace marshal { /// \brief Reference-counted blob of memory to store the object of type T. template class blob : private boost::noncopyable - , public Alloc::template rebind::other + , public std::allocator_traits::template rebind_alloc { - typedef typename Alloc::template rebind::other base_t; - typedef typename Alloc::template rebind >::other blob_alloc_t; + using base_t = typename std::allocator_traits::template rebind_alloc; + using blob_alloc_t = typename std::allocator_traits::template rebind_alloc>; atomic m_rc; const size_t m_size; diff --git a/include/eixx/marshal/eterm_format.hxx b/include/eixx/marshal/eterm_format.hxx index b6bf3ad..275d83d 100644 --- a/include/eixx/marshal/eterm_format.hxx +++ b/include/eixx/marshal/eterm_format.hxx @@ -58,9 +58,13 @@ namespace marshal { template struct vector : public - std::vector, - typename Alloc::template rebind>::other> { - using VecAlloc = typename Alloc::template rebind>::other; + std::vector< + eterm, + typename std::allocator_traits::template rebind_alloc> + > + { + using VecAlloc = typename std::allocator_traits:: + template rebind_alloc>; using base = std::vector, VecAlloc>; explicit vector(const Alloc& a_alloc = Alloc()) : base(a_alloc) diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index f9d2e7c..f2d12a7 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -52,8 +52,8 @@ class eterm_pattern_action; */ template class eterm_pattern_matcher { - using ListAlloc = typename Alloc::template - rebind>::other; + using ListAlloc = typename std::allocator_traits:: + template rebind_alloc>; public: using list_t = std::list, ListAlloc>; using const_iterator = typename list_t::const_iterator; diff --git a/include/eixx/marshal/map.hpp b/include/eixx/marshal/map.hpp index 1a575a3..5ba67fa 100644 --- a/include/eixx/marshal/map.hpp +++ b/include/eixx/marshal/map.hpp @@ -46,7 +46,7 @@ template class eterm; template class map { public: - using MapAlloc = typename Alloc::template rebind, eterm>>::other; + using MapAlloc = typename std::allocator_traits::template rebind_alloc, eterm>>; using MapT = std::map, eterm, std::less>, MapAlloc>; protected: using BlobT = blob; diff --git a/include/eixx/marshal/varbind.hpp b/include/eixx/marshal/varbind.hpp index 816eceb..1f52f12 100644 --- a/include/eixx/marshal/varbind.hpp +++ b/include/eixx/marshal/varbind.hpp @@ -74,7 +74,8 @@ class varbind { using eterm_map_t = std::map< atom, eterm, std::less, - typename Alloc::template rebind>>::other + typename std::allocator_traits:: + template rebind_alloc>> >; public: From 74c3107134982c9111294290229028a93cb6e42d Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 3 May 2021 21:55:33 -0400 Subject: [PATCH 150/185] Revert default build to C++17 --- build-aux/CMakeInit.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-aux/CMakeInit.txt b/build-aux/CMakeInit.txt index 3c5eac5..500fd78 100644 --- a/build-aux/CMakeInit.txt +++ b/build-aux/CMakeInit.txt @@ -5,7 +5,7 @@ SET (CMAKE_C_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g") SET (CMAKE_CXX_FLAGS_INIT "-Wall -march=native -Wno-deprecated -Wno-deprecated-declarations") -SET (CMAKE_CXX_STANDARD 20) +SET (CMAKE_CXX_STANDARD 17) SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g -O0") SET (CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") SET (CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") From 932ac43bb3aea0e5718e8f19bb041f0bb45919cb Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Mon, 9 Aug 2021 19:51:24 +0800 Subject: [PATCH 151/185] fixes for darwin --- CMakeLists.txt | 13 ++++++++++--- build-aux/bootstrap.mk | 14 +++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aaabf7a..56540ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,8 +30,12 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/build-aux/CMakeEx.txt) #------------------------------------------------------------------------------- # See also build/CMakeInit.txt if("${toolchain}" STREQUAL "gcc") - set(CMAKE_C_COMPILER "gcc") - set(CMAKE_CXX_COMPILER "g++") + if(NOT CMAKE_C_COMPILER) + set(CMAKE_C_COMPILER "gcc") + endif() + if(NOT CMAKE_CXX_COMPILER) + set(CMAKE_CXX_COMPILER "g++") + endif() add_definitions(-fopenmp -Wall -Wno-strict-aliasing) if("${CMAKE_BUILD_TYPE}" STREQUAL "release") @@ -185,7 +189,10 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.in" #------------------------------------------------------------------------------- add_subdirectory(${CMAKE_SOURCE_DIR}/src) -add_subdirectory(${CMAKE_SOURCE_DIR}/test) +if(CMAKE_SYSTEM_NAME STREQUAL Linux OR + CMAKE_SYSTEM_NAME STREQUAL Android) + add_subdirectory(${CMAKE_SOURCE_DIR}/test) +endif() #=============================================================================== # Installation diff --git a/build-aux/bootstrap.mk b/build-aux/bootstrap.mk index 72bc0f7..71c6f5d 100644 --- a/build-aux/bootstrap.mk +++ b/build-aux/bootstrap.mk @@ -6,9 +6,9 @@ # Date: 2014-08-12 #------------------------------------------------------------------------------- -PROJECT := $(shell sed -n '/^project/{s/^project. *\([a-zA-Z0-9]\+\).*/\1/p; q}'\ +PROJECT := $(shell sed -n '/^project/{s/^project. *\([a-zA-Z0-9]\{1,\}\).*/\1/p; q;}'\ CMakeLists.txt) -VERSION := $(shell sed -n '/^project/{s/^.\+VERSION \+//; s/[^\.0-9]\+//; p; q}'\ +VERSION := $(shell sed -n '/^project/{s/^.\{1,\}VERSION \{1,\}//; s/[^\.0-9]\{1,\}//; p; q;}'\ CMakeLists.txt) HOSTNAME := $(shell hostname) @@ -61,11 +61,7 @@ endif # Function that replaces variables in a given entry in a file # E.g.: $(call substitute,ENTRY,FILENAME) -substitute = $(shell sed -n '/^$(1)=/{s!$(1)=!!; s!/\+$$!!; \ - s!@PROJECT@!$(PROJECT)!gI; \ - s!@VERSION@!$(VERSION)!gI; \ - s!@BUILD@!$(BUILD)!gI; \ - p; q}' $(2) 2>/dev/null) +substitute = $(shell sed -n '/^$(1)=/{s!$(1)=!!; s!/\{1,\}$$!!; s!@PROJECT@!$(PROJECT)!g; s!@VERSION@!$(VERSION)!g; s!@BUILD@!$(BUILD)!g; p; q;}' $(2) 2>/dev/null) BLD_DIR := $(call substitute,DIR:BUILD,$(OPT_FILE)) ROOT_DIR := $(dir $(abspath include)) DEF_BLD_DIR := $(ROOT_DIR:%/=%)/build @@ -95,8 +91,8 @@ ver: variables := $(filter-out toolchain=% generator=% build=% verbose=% prefix=%,$(MAKEOVERRIDES)) makevars := $(variables:%=-D%) -envvars += $(shell sed -n '/^ENV:/{s/^ENV://;p}' $(OPT_FILE) 2>/dev/null) -makevars += $(patsubst %,-D%,$(shell sed -n '/^...:/!{s/ *\#.*$$//; /^$$/!p}' \ +envvars += $(shell sed -n '/^ENV:/{s/^ENV://;p;}' $(OPT_FILE) 2>/dev/null) +makevars += $(patsubst %,-D%,$(shell sed -n '/^...:/!{s/ *\#.*$$//; /^$$/!p;}' \ $(OPT_FILE) 2>/dev/null)) makecmd = $(envvars) cmake -H. -B$(DIR) \ From d31bc52f3ae0e04a074bc70a13166474c3e842bf Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 9 Aug 2021 11:20:51 -0400 Subject: [PATCH 152/185] Add test case --- build-aux/bootstrap.mk | 1 + test/test_eterm.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/build-aux/bootstrap.mk b/build-aux/bootstrap.mk index 72bc0f7..6b01f3a 100644 --- a/build-aux/bootstrap.mk +++ b/build-aux/bootstrap.mk @@ -134,6 +134,7 @@ bootstrap: | $(DIR) @echo "export VERSION := $(VERSION)" >> $(DIR)/cache.mk @echo "export OPT_FILE := $(abspath $(OPT_FILE))" >> $(DIR)/cache.mk @echo "export generator := $(generator)" >> $(DIR)/cache.mk + @echo "export toolchain := $(toolchain)" >> $(DIR)/cache.mk @echo "export build := $(BUILD)" >> $(DIR)/cache.mk @echo "export DIR := $(DIR)" >> $(DIR)/cache.mk @echo "export prefix := $(prefix)" >> $(DIR)/cache.mk diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 6e5c158..c023446 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -203,6 +203,12 @@ BOOST_AUTO_TEST_CASE( test_list ) eterm et = list(l); BOOST_REQUIRE(et.initialized()); } + { + list l{1, 2, 3, "abc", 2.0, atom("efg")}; + eterm et = l; + BOOST_REQUIRE_EQUAL(6, l.length()); + BOOST_REQUIRE(et.initialized()); + } { eterm items[] = { eterm(atom("abc")), @@ -606,6 +612,12 @@ BOOST_AUTO_TEST_CASE( test_tuple ) BOOST_REQUIRE(et.initialized()); } + { + tuple t{1, 2, 3, "abc", 2.0, atom("efg")}; + eterm et = t; + BOOST_REQUIRE(et.initialized()); + } + eterm l[] = { eterm(atom("abc")), eterm(atom("efg")), From 2253d6417b386086b43291c55444c4e620177ee1 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Fri, 13 Aug 2021 08:20:24 -0400 Subject: [PATCH 153/185] Fix compilation with -Wpedantic --- CMakeLists.txt | 1 + include/eixx/marshal/list.hpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 56540ec..784726c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,7 @@ add_definitions( -D_REENTRANT -Wno-unused-local-typedefs -Wno-deprecated-declarations + -Wpedantic -DBOOST_SYSTEM_NO_DEPRECATED ) diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index e1c434e..283a311 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -62,7 +62,10 @@ class list : protected alloc_base, Alloc> { unsigned int alloc_size; unsigned int size; cons_t* tail; + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpedantic" cons_t head[0]; + #pragma GCC diagnostic pop }; typedef blob blob_t; @@ -385,4 +388,4 @@ namespace std { } // namespace std -#include \ No newline at end of file +#include From af13b9f6fd206075ff7367a28f52bbf77b390f76 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Sat, 14 Aug 2021 02:31:48 +0800 Subject: [PATCH 154/185] fix -Wshadow warning --- include/eixx/marshal/eterm_format.hxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/eixx/marshal/eterm_format.hxx b/include/eixx/marshal/eterm_format.hxx index 275d83d..de0d8be 100644 --- a/include/eixx/marshal/eterm_format.hxx +++ b/include/eixx/marshal/eterm_format.hxx @@ -387,7 +387,7 @@ namespace marshal { const char* end = strstr(++(*fmt), ">>"); if (!end) throw err_format_exception("Cannot find end of binary", *fmt); - std::vector v; + std::vector v2; auto p = *fmt; while (p < end) { @@ -399,15 +399,15 @@ namespace marshal { p = q; if (byte < 0 || byte > 255) throw err_format_exception("Invalid byte value in binary", p); - v.push_back((char)byte); + v2.push_back((char)byte); while (*p == ' ' || *p == '\t') ++p; if (*p == ',') ++p; else if (p < end) throw err_format_exception("Invalid byte delimiter in binary", p); } - auto begin = &v[0]; - ret = eterm(binary(begin, v.size(), alloc)); + auto begin = &v2[0]; + ret = eterm(binary(begin, v2.size(), alloc)); *fmt = end + 2; } break; From b6ecfc300f5c68c42eb689cdac281da74c31d344 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 16 Aug 2021 11:48:33 -0400 Subject: [PATCH 155/185] Fix support of ATOM_UTF8_EXT, SMALL_ATOM_UTF8_EXT --- include/eixx/marshal/atom.hpp | 8 +++++--- include/eixx/marshal/pid.hxx | 7 +++++-- include/eixx/marshal/port.hxx | 7 +++++-- include/eixx/marshal/ref.hxx | 5 +++-- include/eixx/marshal/string.hpp | 9 ++++++++- include/eixx/util/string_util.hpp | 3 ++- test/test_eterm.cpp | 6 +++--- test/test_eterm_encode.cpp | 25 +++++++++++++------------ test/test_eterm_pool.cpp | 2 +- 9 files changed, 45 insertions(+), 27 deletions(-) diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 43a20dc..854fcb1 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -157,8 +157,10 @@ class atom const char *s0 = s; int len; switch (get8(s)) { - case ERL_ATOM_EXT: len = get16be(s); break; - case ERL_SMALL_ATOM_EXT: len = get8(s); break; + case ERL_ATOM_UTF8_EXT: len = get16be(s); break; + case ERL_SMALL_ATOM_UTF8_EXT: len = get8(s); break; + case ERL_ATOM_EXT: len = get16be(s); break; + case ERL_SMALL_ATOM_EXT: len = get8(s); break; default: throw err_decode_exception("Error decoding atom", idx); } m_index = atom_table().lookup(std::string(s, len)); @@ -204,7 +206,7 @@ class atom char* s0 = s; const int len = std::min((size_t)MAXATOMLEN, length()); /* This function is documented to truncate at MAXATOMLEN (256) */ - put8(s,ERL_ATOM_EXT); + put8(s,ERL_ATOM_UTF8_EXT); put16be(s,len); memmove(s,c_str(),len); /* unterminated string */ s += len; diff --git a/include/eixx/marshal/pid.hxx b/include/eixx/marshal/pid.hxx index 22a1863..f14cf47 100644 --- a/include/eixx/marshal/pid.hxx +++ b/include/eixx/marshal/pid.hxx @@ -37,8 +37,11 @@ void epid::decode(const char *buf, int& idx, size_t size, const Alloc& al { const char* s = buf + idx; const char* s0 = s; - if (get8(s) != ERL_PID_EXT || get8(s) != ERL_ATOM_EXT) + if (get8(s) != ERL_PID_EXT) throw err_decode_exception("Error decoding pid", -1); + auto n = get8(s); + if (n != ERL_ATOM_UTF8_EXT && n != ERL_ATOM_EXT) + throw err_decode_exception("Error decoding pid node", -1); int len = get16be(s); detail::check_node_length(len); @@ -63,7 +66,7 @@ void epid::encode(char* buf, int& idx, size_t size) const char* s = buf + idx; char* s0 = s; put8(s,ERL_PID_EXT); - put8(s,ERL_ATOM_EXT); + put8(s,ERL_ATOM_UTF8_EXT); const std::string& nd = node().to_string(); unsigned short n = nd.size(); put16be(s, n); diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index 717bb19..2f7a86e 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -37,8 +37,11 @@ port::port(const char *buf, int& idx, size_t size, const Alloc& a_alloc) { const char* s = buf + idx; const char* s0 = s; - if (get8(s) != ERL_PORT_EXT || get8(s) != ERL_ATOM_EXT) + if (get8(s) != ERL_PORT_EXT) throw err_decode_exception("Error decoding port", -1); + auto n = get8(s); + if (n != ERL_ATOM_UTF8_EXT && n != ERL_ATOM_EXT) + throw err_decode_exception("Error decoding port node", -1); int len = get16be(s); detail::check_node_length(len); atom l_node(s, len); @@ -58,7 +61,7 @@ void port::encode(char* buf, int& idx, size_t size) const char* s = buf + idx; char* s0 = s; put8(s,ERL_PORT_EXT); - put8(s,ERL_ATOM_EXT); + put8(s,ERL_ATOM_UTF8_EXT); const std::string& str = node().to_string(); unsigned short n = str.size(); put16be(s, n); diff --git a/include/eixx/marshal/ref.hxx b/include/eixx/marshal/ref.hxx index 50cfe4c..514eb61 100644 --- a/include/eixx/marshal/ref.hxx +++ b/include/eixx/marshal/ref.hxx @@ -46,7 +46,8 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) int count = get16be(s); if (count != COUNT) throw err_decode_exception("Error decoding ref's count", idx+1); - if (get8(s) != ERL_ATOM_EXT) + auto n = get8(s); + if (n != ERL_ATOM_UTF8_EXT && n != ERL_ATOM_EXT) throw err_decode_exception("Error decoding ref's atom", idx+3); int len = get16be(s); @@ -77,7 +78,7 @@ void ref::encode(char* buf, int& idx, size_t size) const /* first, number of integers */ put16be(s, COUNT); /* then the nodename */ - put8(s,ERL_ATOM_EXT); + put8(s,ERL_ATOM_UTF8_EXT); const std::string& str = node().to_string(); unsigned short n = str.size(); put16be(s, n); diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index 48c9f0e..d995d2d 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -186,6 +186,13 @@ class string ei_encode_string_len(buf, &idx, c_str(), length()); } + template + Stream& to_binary_string(Stream& out) { + return eixx::to_binary_string(out, c_str(), size()); + } + + std::string to_binary_string() const { return eixx::to_binary_string(c_str(), size()); } + std::ostream& dump(std::ostream& out, const varbind* binding=NULL) const { return out << *this; } @@ -193,7 +200,7 @@ class string template static std::string to_binary_string(const string& a) { - return to_binary_string(a.c_str(), a.size()); + return a.to_binary_string(); } template diff --git a/include/eixx/util/string_util.hpp b/include/eixx/util/string_util.hpp index 109666a..5d32f22 100644 --- a/include/eixx/util/string_util.hpp +++ b/include/eixx/util/string_util.hpp @@ -39,7 +39,8 @@ namespace eixx { /// Print the content of a buffer to \a out stream in the form: /// \verbatim <> \endverbatim where Ik is /// unsigned integer less than 256. -inline std::ostream& to_binary_string(std::ostream& out, const char* buf, size_t sz) { +template +inline Stream& to_binary_string(Stream& out, const char* buf, size_t sz) { out << "<<"; const char* begin = buf, *end = buf + sz; for(const char* p = begin; p != end; ++p) { diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index c023446..d43ced0 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -105,7 +105,7 @@ BOOST_AUTO_TEST_CASE( test_atom ) } { - const uint8_t buf[] = {ERL_ATOM_EXT,0,3,97,98,99}; + const uint8_t buf[] = {ERL_ATOM_UTF8_EXT,0,3,97,98,99}; int i = 0; atom atom((const char*)buf, i, sizeof(buf)); BOOST_REQUIRE_EQUAL(6, i); @@ -148,14 +148,14 @@ BOOST_AUTO_TEST_CASE( test_bool ) } { - const uint8_t buf[] = {ERL_ATOM_EXT,0,4,116,114,117,101}; + const uint8_t buf[] = {ERL_ATOM_UTF8_EXT,0,4,116,114,117,101}; int i = 0; eterm t((const char*)buf, i, sizeof(buf), alloc); BOOST_REQUIRE_EQUAL(true, t.to_bool()); BOOST_REQUIRE_EQUAL(std::string("true"), t.to_string()); } { - const uint8_t buf[] = {ERL_ATOM_EXT,0,5,102,97,108,115,101}; + const uint8_t buf[] = {ERL_ATOM_UTF8_EXT,0,5,102,97,108,115,101}; int i = 0; eterm t((const char*)buf, i, sizeof(buf), alloc); BOOST_REQUIRE_EQUAL(sizeof(buf), (size_t)i); diff --git a/test/test_eterm_encode.cpp b/test/test_eterm_encode.cpp index 6a201d5..3300c66 100644 --- a/test/test_eterm_encode.cpp +++ b/test/test_eterm_encode.cpp @@ -21,6 +21,7 @@ limitations under the License. #include #include "test_alloc.hpp" #include +#include using namespace eixx; @@ -45,7 +46,7 @@ BOOST_AUTO_TEST_CASE( test_encode_atom ) { eterm a(atom("abc")); string s(a.encode(0)); - const uint8_t expect[] = {131,100,0,3,97,98,99}; + const uint8_t expect[] = {131,ERL_ATOM_UTF8_EXT,0,3,97,98,99}; BOOST_REQUIRE(s.equal(expect)); int idx = 1; // skipping the magic byte atom t1((const char*)expect, idx, sizeof(expect)); @@ -99,8 +100,8 @@ BOOST_AUTO_TEST_CASE( test_encode_list ) list l(ll); eterm t(l); string s(t.encode(0)); - const uint8_t expect[] = {131,108,0,0,0,4,100,0,3,97,98,99,107,0,2,101,102, - 97,1,107,0,2,103,104,106}; + const uint8_t expect[] = {131,108,0,0,0,4,ERL_ATOM_UTF8_EXT,0,3,97,98,99, + 107,0,2,101,102,97,1,107,0,2,103,104,106}; BOOST_REQUIRE(s.equal(expect)); int idx = 1; // skipping the magic byte list t1((const char*)expect, idx, sizeof(expect)); @@ -159,7 +160,7 @@ BOOST_AUTO_TEST_CASE( test_encode_pid ) string s(t.encode(0)); //std::cout << s.to_binary_string() << std::endl; const uint8_t expect[] = - {131,103,100,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0,0,0,2,0}; + {131,103,ERL_ATOM_UTF8_EXT,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0,0,0,2,0}; BOOST_REQUIRE(s.equal(expect)); int idx = 1; // skipping the magic byte eterm pid(epid((const char*)expect, idx, sizeof(expect))); @@ -167,7 +168,7 @@ BOOST_AUTO_TEST_CASE( test_encode_pid ) } { const uint8_t expect[] = - {131,103,100,0,8,97,98,99,64,102,99,49,50,0,0,0,96,0,0,0,0,3}; + {131,103,ERL_ATOM_UTF8_EXT,0,8,97,98,99,64,102,99,49,50,0,0,0,96,0,0,0,0,3}; int idx = 1; // skipping the magic byte epid decode_pid((const char*)expect, idx, sizeof(expect)); epid expect_pid("abc@fc12", 96, 0, 3); @@ -182,7 +183,7 @@ BOOST_AUTO_TEST_CASE( test_encode_port ) string s(t.encode(0)); //std::cout << s.to_binary_string() << std::endl; const uint8_t expect[] = - {131,102,100,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0}; + {131,102,ERL_ATOM_UTF8_EXT,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0}; BOOST_REQUIRE(s.equal(expect)); int idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); @@ -196,7 +197,7 @@ BOOST_AUTO_TEST_CASE( test_encode_ref ) BOOST_REQUIRE_EQUAL("#Ref", t.to_string()); string s(t.encode(0)); //std::cout << s.to_binary_string() << std::endl; - const uint8_t expect[] = {131,114,0,3,100,0,9,116,101,115,116,64,104,111,115, + const uint8_t expect[] = {131,114,0,3,ERL_ATOM_UTF8_EXT,0,9,116,101,115,116,64,104,111,115, 116,0,0,0,0,1,0,0,0,2,0,0,0,3}; BOOST_REQUIRE(s.equal(expect)); int idx = 1; // skipping the magic byte @@ -205,7 +206,7 @@ BOOST_AUTO_TEST_CASE( test_encode_ref ) { ref t(atom("abc@fc12"), 993, 0, 0, 2); const uint8_t expect[] = - {131,114,0,3,100,0,8,97,98,99,64,102,99,49,50,2,0,0,3,225,0,0,0,0,0,0,0,0}; + {131,114,0,3,ERL_ATOM_UTF8_EXT,0,8,97,98,99,64,102,99,49,50,2,0,0,3,225,0,0,0,0,0,0,0,0}; int idx = 1; // skipping the magic byte ref t1((const char*)expect, idx, sizeof(expect)); BOOST_REQUIRE_EQUAL(t1, t); @@ -231,8 +232,8 @@ BOOST_AUTO_TEST_CASE( test_encode_tuple ) eterm t(tup); string s(t.encode(0)); //std::cout << s.to_binary_string() << std::endl; - const uint8_t expect[] = {131,104,5,100,0,3,97,98,99,107,0,2,101,102,97,1, - 104,4,100,0,1,97,107,0,2,120,120,70,64,94,198,102, + const uint8_t expect[] = {131,104,5,ERL_ATOM_UTF8_EXT,0,3,97,98,99,107,0,2,101,102,97,1, + 104,4,ERL_ATOM_UTF8_EXT,0,1,97,107,0,2,120,120,70,64,94,198,102, 102,102,102,102,97,5,107,0,2,103,104}; BOOST_REQUIRE(s.equal(expect)); int idx = 1; // skipping the magic byte @@ -247,8 +248,8 @@ BOOST_AUTO_TEST_CASE( test_encode_trace ) trace tr(1,2,3,self,4); eterm t(tr); string s(t.encode(0)); - //std::cout << s.to_binary_string() << std::endl; - const uint8_t expect[] = {131,104,5,97,1,97,2,97,3,103,100,0,8,97,98,99,64, + //std::cout << to_binary_string(s) << std::endl; + const uint8_t expect[] = {131,104,5,97,1,97,2,97,3,103,ERL_ATOM_UTF8_EXT,0,8,97,98,99,64, 102,99,49,50,0,0,0,96,0,0,0,0,3,97,4}; BOOST_REQUIRE(s.equal(expect)); int idx = 1; // skipping the magic byte diff --git a/test/test_eterm_pool.cpp b/test/test_eterm_pool.cpp index 5095f98..02fa504 100644 --- a/test/test_eterm_pool.cpp +++ b/test/test_eterm_pool.cpp @@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE( test_encode_atom_t ) { atom a("abc"); string s(eterm(a).encode(0)); - const uint8_t expect[] = {131,100,0,3,97,98,99}; + const uint8_t expect[] = {131,ERL_ATOM_UTF8_EXT,0,3,97,98,99}; BOOST_REQUIRE(s.equal(expect)); } From 2c8116a43457c5d6780269b942c812d61df64183 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Tue, 17 Aug 2021 02:03:37 +0800 Subject: [PATCH 156/185] Support Boost v1.66+ and OTP v20 to v22 --- CMakeLists.txt | 14 +-------- include/eixx/connect/basic_otp_mailbox.hpp | 2 +- include/eixx/connect/transport_msg.hpp | 5 ++-- .../eixx/connect/transport_otp_connection.hpp | 16 ++++++++-- .../eixx/connect/transport_otp_connection.hxx | 6 ++-- .../connect/transport_otp_connection_tcp.hpp | 16 ++++++++-- .../connect/transport_otp_connection_tcp.hxx | 16 ++++++++-- .../connect/transport_otp_connection_uds.hpp | 12 +++++++- include/eixx/eixx.hpp | 2 -- include/eixx/marshal/atom.hpp | 30 ++++++++++++++----- include/eixx/marshal/eterm.hxx | 9 ++++++ include/eixx/marshal/pid.hxx | 7 ++--- include/eixx/marshal/port.hxx | 6 ++-- include/eixx/marshal/ref.hxx | 7 ++--- include/eixx/util/common.hpp | 2 +- src/basic_otp_node_local.cpp | 4 --- src/server.hpp | 4 --- src/test_node.cpp | 2 +- test/CMakeLists.txt | 1 - 19 files changed, 103 insertions(+), 58 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 784726c..7529dfa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,9 +122,7 @@ set(Boost_USE_MULTITHREAD ON) set(Boost_NO_SYSTEM_PATHS ON) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/build") -find_package(Boost 1.55.0 REQUIRED COMPONENTS - system filesystem date_time program_options thread regex - unit_test_framework timer) +find_package(Boost 1.55.0 REQUIRED COMPONENTS system thread) if(Boost_FOUND) #include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) @@ -133,16 +131,6 @@ if(Boost_FOUND) message(STATUS "Found boost: ${Boost_LIBRARY_DIRS}") endif() -set(Boost_LIBRARIES - boost_system - boost_thread -# ${Boost_REGEX_LIBRARY} -# ${Boost_DATE_TIME_LIBRARY} -# ${Boost_FILESYSTEM_LIBRARY} -# ${Boost_PROGRAM_OPTIONS_LIBRARY} -# ${Boost_IOSTREAMS_LIBRARY} -) - #------------------------------------------------------------------------------- # Platform-specific checks #------------------------------------------------------------------------------- diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index d221769..591afc9 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -101,7 +101,7 @@ class basic_otp_mailbox template friend struct util::async_queue; template friend class basic_otp_mailbox_registry; template friend class std::function; - template friend class std::_Function_handler; + // template friend class std::_Function_handler; private: boost::asio::io_service& m_io_service; diff --git a/include/eixx/connect/transport_msg.hpp b/include/eixx/connect/transport_msg.hpp index cb6eb08..5bb80fa 100644 --- a/include/eixx/connect/transport_msg.hpp +++ b/include/eixx/connect/transport_msg.hpp @@ -450,8 +450,9 @@ const char* transport_msg::type_string() const { case DEMONITOR_P: return "DEMONITOR_P"; case MONITOR_P_EXIT: return "MONITOR_P_EXIT"; default: { - std::stringstream str; str << "UNSUPPORTED(" << bit_scan_forward(m_type) << ')'; - return str.str().c_str(); + // std::stringstream str; str << "UNSUPPORTED(" << bit_scan_forward(m_type) << ')'; + // return str.str().c_str(); + return "UNSUPPORTED"; } } } diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index 7ea9b43..e178881 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -141,21 +141,33 @@ class connection void do_write_internal() { if (!m_is_writing && !m_out_msg_queue[available_queue()].empty()) { +#if BOOST_VERSION >= 106600 + std::deque buffers = m_out_msg_queue[available_queue()]; +#else typedef boost::asio::detail::consuming_buffers< boost::asio::const_buffer, std::deque > cb_t; cb_t buffers(m_out_msg_queue[available_queue()]); +#endif m_is_writing = true; flip_queues(); // Work on the data accumulated in the available_queue. - if (unlikely(verbose() >= VERBOSE_WIRE)) - for(cb_t::const_iterator it=buffers.begin(); it != buffers.end(); ++it) { + if (unlikely(verbose() >= VERBOSE_WIRE)) { +#if BOOST_VERSION >= 106600 + auto begin = boost::asio::buffer_sequence_begin(buffers); + auto end = boost::asio::buffer_sequence_end(buffers); +#else + auto begin = buffers.begin(); + auto end = buffers.end(); +#endif + for(auto it=begin; it != end; ++it) { std::stringstream s; s << " async_write " << boost::asio::buffer_size(*it) << " bytes: " << to_binary_string(boost::asio::buffer_cast(*it), boost::asio::buffer_size(*it)); m_handler->report_status(REPORT_INFO, s.str()); } + } auto pthis = this->shared_from_this(); async_write(buffers, boost::asio::transfer_all(), [pthis](auto& ec, std::size_t) { pthis->handle_write(ec); }); diff --git a/include/eixx/connect/transport_otp_connection.hxx b/include/eixx/connect/transport_otp_connection.hxx index cf81e5a..da505fb 100644 --- a/include/eixx/connect/transport_otp_connection.hxx +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -44,7 +44,7 @@ template const size_t connection::s_header_size = 4; template -const char connection::s_header_magic = 132; +const char connection::s_header_magic = static_cast(132); template const eterm connection::s_null_cookie; @@ -172,7 +172,7 @@ handle_write(const boost::system::error_code& err) return; } - if (unlikely(err)) { + if (unlikely(bool(err))) { if (verbose() >= VERBOSE_TRACE) { std::stringstream s; s << "connection::handle_write(" << err.value() << ')'; @@ -223,7 +223,7 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) "Connection aborted - exiting connection::handle_read"); } return; - } else if (unlikely(err)) { + } else if (unlikely(bool(err))) { // We use operation_aborted as a user-initiated connection reset, // therefore check to substitute the error since bytes_transferred == 0 // means a connection loss. diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 5507719..fa333e8 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -62,7 +62,13 @@ static const int DFLAG_DIST_MONITOR = 8; static const int DFLAG_FUN_TAGS = 16; static const int DFLAG_NEW_FUN_TAGS = 0x80; static const int DFLAG_EXTENDED_PIDS_PORTS = 0x100; +static const int DFLAG_EXPORT_PTR_TAG = 0x200; +static const int DFLAG_BIT_BINARIES = 0x400; static const int DFLAG_NEW_FLOATS = 0x800; +static const int DFLAG_SMALL_ATOM_TAGS = 0x4000; +static const int DFLAG_UTF8_ATOMS = 0x10000; +static const int DFLAG_MAP_TAG = 0x20000; +static const int DFLAG_BIG_CREATION = 0x40000; #endif //---------------------------------------------------------------------------- @@ -100,7 +106,13 @@ class tcp_connection return s.str(); } - int native_socket() { return m_socket.native(); } + int native_socket() { +#if BOOST_VERSION >= 104700 + return m_socket.native_handle(); +#else + return m_socket.native(); +#endif + } private: /// Authentication state @@ -141,7 +153,7 @@ class tcp_connection boost::shared_ptr > shared_from_this() { boost::shared_ptr > p = base_t::shared_from_this(); - return *reinterpret_cast >*>(&p); + return boost::reinterpret_pointer_cast >(p); } /// Set the socket to non-blocking mode and issue on_connect() callback. diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index 1dd936d..4f06b21 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -42,8 +42,12 @@ namespace connect { template void tcp_connection::start() { +#if BOOST_VERSION >= 104700 + m_socket.non_blocking(true); +#else boost::asio::ip::tcp::socket::non_blocking_io nb(true); m_socket.io_control(nb); +#endif base_t::start(); // trigger on_connect callback } @@ -331,12 +335,20 @@ void tcp_connection::handle_connect(const boost::system::error_c put16be(w, siz - 2); put8(w, 'n'); put16be(w, m_dist_version); - put32be(w, ( DFLAG_EXTENDED_REFERENCES + unsigned int flags = (DFLAG_EXTENDED_REFERENCES + | DFLAG_DIST_MONITOR | DFLAG_EXTENDED_PIDS_PORTS | DFLAG_FUN_TAGS | DFLAG_NEW_FUN_TAGS | DFLAG_NEW_FLOATS - | DFLAG_DIST_MONITOR)); + | DFLAG_SMALL_ATOM_TAGS + | DFLAG_UTF8_ATOMS + | DFLAG_MAP_TAG + // | DFLAG_BIG_CREATION + // | DFLAG_EXPORT_PTR_TAG + // | DFLAG_BIT_BINARIES + ); + put32be(w, flags); memcpy(w, this->local_nodename().c_str(), this->local_nodename().size()); if (this->handler()->verbose() >= VERBOSE_TRACE) { diff --git a/include/eixx/connect/transport_otp_connection_uds.hpp b/include/eixx/connect/transport_otp_connection_uds.hpp index 8205d7b..17da638 100644 --- a/include/eixx/connect/transport_otp_connection_uds.hpp +++ b/include/eixx/connect/transport_otp_connection_uds.hpp @@ -59,8 +59,12 @@ class uds_connection boost::asio::local::stream_protocol::socket& socket() { return m_socket; } void start() { +#if BOOST_VERSION >= 104700 + m_socket.non_blocking(true); +#else boost::asio::local::stream_protocol::socket::non_blocking_io nb(true); m_socket.io_control(nb); +#endif base_t::start(); } @@ -70,7 +74,13 @@ class uds_connection return m_uds_filename; } - int native_socket() { return m_socket.native(); } + int native_socket() { +#if BOOST_VERSION >= 104700 + return m_socket.native_handle(); +#else + return m_socket.native(); +#endif + } private: /// Socket for the connection. diff --git a/include/eixx/eixx.hpp b/include/eixx/eixx.hpp index 9adb05d..54bf6d5 100644 --- a/include/eixx/eixx.hpp +++ b/include/eixx/eixx.hpp @@ -59,9 +59,7 @@ limitations under the License. #endif #include -#if BOOST_VERSION < 106000 #include -#endif #endif // _EIXX_HPP_ diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 854fcb1..aba64c8 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -113,6 +113,25 @@ class atom return create(std::string(s), existing); } + /// Get atom length from a binary buffer encoded in + /// Erlang external binary format. + static int getLen(const char*& s) { + switch (get8(s)) { +#ifdef ERL_SMALL_ATOM_UTF8_EXT + case ERL_SMALL_ATOM_UTF8_EXT: return get8(s); +#endif +#ifdef ERL_ATOM_UTF8_EXT + case ERL_ATOM_UTF8_EXT: return get16be(s); +#endif +#ifdef ERL_SMALL_ATOM_EXT + case ERL_SMALL_ATOM_EXT: return get8(s); +#endif + case ERL_ATOM_EXT: return get16be(s); + default: + return -1; + } + } + /// @copydoc atom::atom /// @param existing if true, check that the atom already exists, otherwise throw /// err_atom_not_found @@ -155,14 +174,9 @@ class atom { const char *s = a_buf + idx; const char *s0 = s; - int len; - switch (get8(s)) { - case ERL_ATOM_UTF8_EXT: len = get16be(s); break; - case ERL_SMALL_ATOM_UTF8_EXT: len = get8(s); break; - case ERL_ATOM_EXT: len = get16be(s); break; - case ERL_SMALL_ATOM_EXT: len = get8(s); break; - default: throw err_decode_exception("Error decoding atom", idx); - } + int len = getLen(s); + if (len < 0) + throw err_decode_exception("Error decoding atom", idx); m_index = atom_table().lookup(std::string(s, len)); idx += s + len - s0; BOOST_ASSERT((size_t)idx <= a_size); diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index 8872f99..6f5f5e1 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -235,6 +235,15 @@ void eterm::decode(const char* a_buf, int& idx, size_t a_size, const Allo throw err_decode_exception("Cannot determine term type", idx); switch (type) { +#ifdef ERL_ATOM_UTF8_EXT + case ERL_ATOM_UTF8_EXT: +#endif +#ifdef ERL_SMALL_ATOM_UTF8_EXT + case ERL_SMALL_ATOM_UTF8_EXT: +#endif +#ifdef ERL_SMALL_ATOM_EXT + case ERL_SMALL_ATOM_EXT: +#endif case ERL_ATOM_EXT: { int b; int i = idx; // TODO: Eliminate this variable when there's is a fix for the bug in ei_decode_boolean diff --git a/include/eixx/marshal/pid.hxx b/include/eixx/marshal/pid.hxx index f14cf47..af24cc5 100644 --- a/include/eixx/marshal/pid.hxx +++ b/include/eixx/marshal/pid.hxx @@ -39,11 +39,10 @@ void epid::decode(const char *buf, int& idx, size_t size, const Alloc& al const char* s0 = s; if (get8(s) != ERL_PID_EXT) throw err_decode_exception("Error decoding pid", -1); - auto n = get8(s); - if (n != ERL_ATOM_UTF8_EXT && n != ERL_ATOM_EXT) - throw err_decode_exception("Error decoding pid node", -1); - int len = get16be(s); + int len = atom::getLen(s); + if (len < 0) + throw err_decode_exception("Error decoding pid node", -1); detail::check_node_length(len); atom l_node(s, len); diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index 2f7a86e..55c64c4 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -39,10 +39,10 @@ port::port(const char *buf, int& idx, size_t size, const Alloc& a_alloc) const char* s0 = s; if (get8(s) != ERL_PORT_EXT) throw err_decode_exception("Error decoding port", -1); - auto n = get8(s); - if (n != ERL_ATOM_UTF8_EXT && n != ERL_ATOM_EXT) + + int len = atom::getLen(s); + if (len < 0) throw err_decode_exception("Error decoding port node", -1); - int len = get16be(s); detail::check_node_length(len); atom l_node(s, len); s += len; diff --git a/include/eixx/marshal/ref.hxx b/include/eixx/marshal/ref.hxx index 514eb61..102bbae 100644 --- a/include/eixx/marshal/ref.hxx +++ b/include/eixx/marshal/ref.hxx @@ -46,11 +46,10 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) int count = get16be(s); if (count != COUNT) throw err_decode_exception("Error decoding ref's count", idx+1); - auto n = get8(s); - if (n != ERL_ATOM_UTF8_EXT && n != ERL_ATOM_EXT) - throw err_decode_exception("Error decoding ref's atom", idx+3); - int len = get16be(s); + int len = atom::getLen(s); + if (len < 0) + throw err_decode_exception("Error decoding ref's atom", idx+3); detail::check_node_length(len); atom l_node(s, len); s += len; diff --git a/include/eixx/util/common.hpp b/include/eixx/util/common.hpp index 073ec6a..1c79499 100644 --- a/include/eixx/util/common.hpp +++ b/include/eixx/util/common.hpp @@ -31,7 +31,7 @@ namespace eixx { -#if BOOST_VERSION > 104800 +#if BOOST_VERSION >= 104800 namespace bid = boost::interprocess::ipcdetail; #else namespace bid = boost::interprocess::detail; diff --git a/src/basic_otp_node_local.cpp b/src/basic_otp_node_local.cpp index e01fa5d..a6d896c 100644 --- a/src/basic_otp_node_local.cpp +++ b/src/basic_otp_node_local.cpp @@ -19,8 +19,6 @@ limitations under the License. */ #include -#if BOOST_VERSION < 106500 - #include #include #include @@ -126,5 +124,3 @@ void basic_otp_node_local::set_nodename( } // namespace connect } // namespace eixx - -#endif // BOOST_VERSION \ No newline at end of file diff --git a/src/server.hpp b/src/server.hpp index 48d2ef2..8d769c9 100644 --- a/src/server.hpp +++ b/src/server.hpp @@ -12,8 +12,6 @@ #include -#if BOOST_VERSION < 106500 - #include #include #include @@ -341,5 +339,3 @@ class uds_server : public server< Handler > }; } // namespace eixx - -#endif // BOOST_VERSION \ No newline at end of file diff --git a/src/test_node.cpp b/src/test_node.cpp index e83d110..d8815f6 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -67,7 +67,7 @@ bool on_main_msg(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) { struct timeval tv = { l_binding[N1]->to_long() * 1000000 + l_binding[N2]->to_long(), - l_binding[N3]->to_long() }; + static_cast(l_binding[N3]->to_long()) }; struct tm tm; localtime_r(&tv.tv_sec, &tm); printf( diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7ed9119..d0942f9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -26,7 +26,6 @@ target_link_libraries( eixx ${Erlang_EI_LIBRARIES} ${Boost_LIBRARIES} - boost_system ) add_executable(test-perf test_perf.cpp) From 66723c55ee3505fe2b54ec539a3df4fbaae1ff50 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Fri, 20 Aug 2021 11:45:27 +0800 Subject: [PATCH 157/185] Rename atom::get_len --- include/eixx/marshal/atom.hpp | 4 ++-- include/eixx/marshal/pid.hxx | 2 +- include/eixx/marshal/port.hxx | 2 +- include/eixx/marshal/ref.hxx | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index aba64c8..d9dd727 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -115,7 +115,7 @@ class atom /// Get atom length from a binary buffer encoded in /// Erlang external binary format. - static int getLen(const char*& s) { + static int get_len(const char*& s) { switch (get8(s)) { #ifdef ERL_SMALL_ATOM_UTF8_EXT case ERL_SMALL_ATOM_UTF8_EXT: return get8(s); @@ -174,7 +174,7 @@ class atom { const char *s = a_buf + idx; const char *s0 = s; - int len = getLen(s); + int len = get_len(s); if (len < 0) throw err_decode_exception("Error decoding atom", idx); m_index = atom_table().lookup(std::string(s, len)); diff --git a/include/eixx/marshal/pid.hxx b/include/eixx/marshal/pid.hxx index af24cc5..52eded6 100644 --- a/include/eixx/marshal/pid.hxx +++ b/include/eixx/marshal/pid.hxx @@ -40,7 +40,7 @@ void epid::decode(const char *buf, int& idx, size_t size, const Alloc& al if (get8(s) != ERL_PID_EXT) throw err_decode_exception("Error decoding pid", -1); - int len = atom::getLen(s); + int len = atom::get_len(s); if (len < 0) throw err_decode_exception("Error decoding pid node", -1); detail::check_node_length(len); diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index 55c64c4..8768770 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -40,7 +40,7 @@ port::port(const char *buf, int& idx, size_t size, const Alloc& a_alloc) if (get8(s) != ERL_PORT_EXT) throw err_decode_exception("Error decoding port", -1); - int len = atom::getLen(s); + int len = atom::get_len(s); if (len < 0) throw err_decode_exception("Error decoding port node", -1); detail::check_node_length(len); diff --git a/include/eixx/marshal/ref.hxx b/include/eixx/marshal/ref.hxx index 102bbae..7626c51 100644 --- a/include/eixx/marshal/ref.hxx +++ b/include/eixx/marshal/ref.hxx @@ -47,7 +47,7 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) if (count != COUNT) throw err_decode_exception("Error decoding ref's count", idx+1); - int len = atom::getLen(s); + int len = atom::get_len(s); if (len < 0) throw err_decode_exception("Error decoding ref's atom", idx+3); detail::check_node_length(len); From 731c1f396f268907781c21cf66b10d34c634ce6b Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Fri, 20 Aug 2021 00:45:00 -0400 Subject: [PATCH 158/185] Remove dynamic exceptions deprecated in C++17 --- CMakeLists.txt | 1 + include/eixx/connect/basic_otp_connection.hpp | 2 +- include/eixx/connect/basic_otp_mailbox.hpp | 12 ++-- include/eixx/connect/basic_otp_mailbox.hxx | 4 +- .../connect/basic_otp_mailbox_registry.hpp | 6 +- .../connect/basic_otp_mailbox_registry.hxx | 5 +- include/eixx/connect/basic_otp_node.hpp | 56 +++++++------------ include/eixx/connect/basic_otp_node.hxx | 25 ++------- include/eixx/connect/basic_otp_node_local.hpp | 6 +- include/eixx/connect/transport_msg.hpp | 18 ++++-- .../eixx/connect/transport_otp_connection.hpp | 7 +-- .../eixx/connect/transport_otp_connection.hxx | 3 +- .../connect/transport_otp_connection_tcp.hpp | 3 +- .../connect/transport_otp_connection_tcp.hxx | 2 +- .../connect/transport_otp_connection_uds.hpp | 1 - 15 files changed, 59 insertions(+), 92 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7529dfa..a947dbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,7 @@ add_definitions( -Wno-deprecated-declarations -Wpedantic -DBOOST_SYSTEM_NO_DEPRECATED + -DBOOST_BIND_GLOBAL_PLACEHOLDERS ) message(STATUS "Configuring for the " diff --git a/include/eixx/connect/basic_otp_connection.hpp b/include/eixx/connect/basic_otp_connection.hpp index 2d74539..146d248 100644 --- a/include/eixx/connect/basic_otp_connection.hpp +++ b/include/eixx/connect/basic_otp_connection.hpp @@ -152,7 +152,7 @@ class basic_otp_connection m_transport->stop(); } - void send(const transport_msg& a_msg) throw (err_connection) { + void send(const transport_msg& a_msg) { if (!m_transport) { if (m_abort) return; diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index 591afc9..84b7ea1 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -200,6 +200,7 @@ class basic_otp_mailbox * @param a_timeout is the timeout interval to wait for message (-1 = infinity) * @param a_repeat_count is the number of messages to wait (-1 = infinite) * @return true if the message was synchronously received + * @throw std::runtime_error **/ template bool async_receive @@ -207,8 +208,7 @@ class basic_otp_mailbox const OnReceive& h, std::chrono::milliseconds a_timeout = std::chrono::milliseconds(-1), int a_repeat_count = 0 - ) - throw (std::runtime_error); + ); /** * Cancel pending asynchronous receive operation @@ -227,6 +227,7 @@ class basic_otp_mailbox * void on_timeout(basic_otp_mailbox&); * \endcode * @param a_repeat_count number of messages to wait (-1 = infinite) + * @throw std::runtime_error */ template bool async_match @@ -235,8 +236,7 @@ class basic_otp_mailbox const OnTimeout& a_on_timeout, std::chrono::milliseconds a_timeout = std::chrono::milliseconds(-1), int a_repeat_count = 0 - ) - throw (std::runtime_error); + ); /// Deliver a message to this mailbox. The call is thread-safe. void deliver(const transport_msg& a_msg) { @@ -298,7 +298,7 @@ class basic_otp_mailbox void send_rpc_cast(const atom& a_node, const atom& a_mod, const atom& a_fun, const list& args, const epid* gleader = NULL) - throw (err_bad_argument, err_no_process, err_connection) { + { m_node.send_rpc_cast(self(), a_node, a_mod, a_fun, args, gleader); } @@ -315,7 +315,7 @@ class basic_otp_mailbox /// The given pid will receive an exit message when \a a_pid dies. /// @throws err_no_process /// @throws err_connection - void link(const epid& a_to) throw (err_no_process, err_connection) { + void link(const epid& a_to) { if (self() == a_to) return; if (m_links.find(a_to) != m_links.end()) diff --git a/include/eixx/connect/basic_otp_mailbox.hxx b/include/eixx/connect/basic_otp_mailbox.hxx index 8dfa6fe..62eee4b 100644 --- a/include/eixx/connect/basic_otp_mailbox.hxx +++ b/include/eixx/connect/basic_otp_mailbox.hxx @@ -51,7 +51,7 @@ template template bool basic_otp_mailbox:: async_receive(const OnReceive& h, std::chrono::milliseconds a_timeout, - int a_repeat_count) throw (std::runtime_error) + int a_repeat_count) { return m_queue->async_dequeue( [this, &h](transport_msg*& a_msg, const boost::system::error_code& ec) { @@ -81,7 +81,7 @@ bool basic_otp_mailbox:: async_match(const marshal::eterm_pattern_matcher& a_matcher, const OnTimeout& a_on_timeout, std::chrono::milliseconds a_timeout, - int a_repeat_count) throw (std::runtime_error) + int a_repeat_count) { auto f = [this, &a_matcher, &a_on_timeout] diff --git a/include/eixx/connect/basic_otp_mailbox_registry.hpp b/include/eixx/connect/basic_otp_mailbox_registry.hpp index 7a3e756..b449b5c 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.hpp +++ b/include/eixx/connect/basic_otp_mailbox_registry.hpp @@ -83,7 +83,7 @@ struct basic_otp_mailbox_registry { * Look up a mailbox based on its name or pid. */ mailbox_ptr - get(const eterm& a_proc) const throw (err_bad_argument, err_no_process); + get(const eterm& a_proc) const; /** * Look up a mailbox based on its name. If the mailbox has gone out @@ -91,7 +91,7 @@ struct basic_otp_mailbox_registry { * don't find it again. */ mailbox_ptr - get(atom a_name) const throw(err_no_process); + get(atom a_name) const; /** * Look up a mailbox based on its pid. If the mailbox has gone out @@ -99,7 +99,7 @@ struct basic_otp_mailbox_registry { * don't find it again. */ mailbox_ptr - get(const epid& a_pid) const throw(err_no_process); + get(const epid& a_pid) const; void names(std::list& list); diff --git a/include/eixx/connect/basic_otp_mailbox_registry.hxx b/include/eixx/connect/basic_otp_mailbox_registry.hxx index 14d8017..291d83e 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.hxx +++ b/include/eixx/connect/basic_otp_mailbox_registry.hxx @@ -157,7 +157,7 @@ erase(mailbox_ptr a_mbox) template typename basic_otp_mailbox_registry::mailbox_ptr basic_otp_mailbox_registry:: -get(const eterm& a_proc) const throw (err_bad_argument, err_no_process) +get(const eterm& a_proc) const { switch (a_proc.type()) { case ATOM: return get(a_proc.to_atom()); @@ -174,7 +174,7 @@ get(const eterm& a_proc) const throw (err_bad_argument, err_no_process) template typename basic_otp_mailbox_registry::mailbox_ptr basic_otp_mailbox_registry:: -get(atom a_name) const throw(err_no_process) +get(atom a_name) const { lock_guard guard(m_lock); typename std::map::iterator it = m_by_name.find(a_name); @@ -191,7 +191,6 @@ get(atom a_name) const throw(err_no_process) template typename basic_otp_mailbox_registry::mailbox_ptr basic_otp_mailbox_registry::get(const epid& a_pid) const - throw(err_no_process) { lock_guard guard(m_lock); typename std::map, mailbox_ptr>::iterator it = m_by_pid.find(a_pid); diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index c49b98b..88f82b2 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -107,17 +107,16 @@ class basic_otp_node: public basic_otp_node_local { protected: /// Publish the node port to epmd making this node known to the world. - void publish_port() throw (err_connection); + void publish_port(); /// Unregister this node from epmd. - void unpublish_port() throw (err_connection); + void unpublish_port(); /// Send a message to a process ToProc which is either epid or /// atom for registered names. template void send(const atom& a_to_node, - ToProc a_to, const transport_msg& a_msg) - throw (err_no_process, err_connection); + ToProc a_to, const transport_msg& a_msg); public: typedef basic_otp_mailbox_registry mailbox_registry_t; @@ -140,8 +139,7 @@ class basic_otp_node: public basic_otp_node_local { const std::string& a_nodename = std::string(), const std::string& a_cookie = std::string(), const Alloc& a_alloc = Alloc(), - int8_t a_creation = -1) - throw (err_bad_argument, err_connection, eterm_exception); + int8_t a_creation = -1); virtual ~basic_otp_node() { close(); } @@ -223,8 +221,7 @@ class basic_otp_node: public basic_otp_node_local { */ template void connect(CompletionHandler h, const atom& a_remote_node, - const atom& a_cookie = atom(), size_t a_reconnect_secs = 0) - throw(err_connection); + const atom& a_cookie = atom(), size_t a_reconnect_secs = 0); /** * Set up a connection to an Erlang node, using default cookie @@ -236,7 +233,7 @@ class basic_otp_node: public basic_otp_node_local { */ template void connect(CompletionHandler h, const atom& a_remote_nodename, - size_t a_reconnect_secs = 0) throw(err_connection); + size_t a_reconnect_secs = 0); /// Get connection identified by the \a a_node name. /// @throws err_connection if not connected to \a a_node._ @@ -270,7 +267,7 @@ class basic_otp_node: public basic_otp_node_local { * registers the port with local epmd daemon. * @throws err_connection if cannot connect to epmd. */ - void start_server() throw(err_connection); + void start_server(); /** * Stop accepting connections from client processes. @@ -280,31 +277,27 @@ class basic_otp_node: public basic_otp_node_local { void stop_server(); /// Deliver a message to its local receipient mailbox. - void deliver(const transport_msg& a_tm) - throw (err_bad_argument, err_no_process, err_connection); + void deliver(const transport_msg& a_tm); /// Send a message \a a_msg from \a a_from pid to \a a_to pid. /// @param a_to is a remote process. /// @param a_msg is the message to send. - void send(const epid& a_to, const eterm& a_msg) - throw (err_no_process, err_connection); + void send(const epid& a_to, const eterm& a_msg); /// Send a message \a a_msg to the remote process \a a_to on node \a a_node. /// The remote process \a a_to need not belong to node \a a_node. /// @param a_node is the node to send the message to. /// @param a_to is a remote process. /// @param a_msg is the message to send. - void send(const atom& a_node, const epid& a_to, const eterm& a_msg) - throw (err_no_process, err_connection); + void send(const atom& a_node, const epid& a_to, const eterm& a_msg); /// Send a message \a a_msg to the local process registered as \a a_to. - void send(const epid& a_from, const atom& a_to, const eterm& a_msg) - throw (err_no_process, err_connection); + void send(const epid& a_from, const atom& a_to, const eterm& a_msg); /// Send a message \a a_msg to the process registered as \a a_to_name /// on remote node \a a_node. void send(const epid& a_from, const atom& a_to_node, const atom& a_to_name, - const eterm& a_msg) throw (err_no_process, err_connection); + const eterm& a_msg); /** * Send an RPC request to a remote Erlang node. @@ -323,47 +316,40 @@ class basic_otp_node: public basic_otp_node_local { */ void send_rpc(const epid& a_from, const atom& a_to_node, const atom& a_mod, const atom& a_fun, const list& args, - const epid* gleader = NULL) - throw (err_bad_argument, err_no_process, err_connection); + const epid* gleader = NULL); /// Execute an equivalent of rpc:cast(...). Doesn't return any value. void send_rpc_cast(const epid& a_from, const atom& a_to_node, const atom& a_mod, const atom& a_fun, const list& args, - const epid* gleader = NULL) - throw (err_bad_argument, err_no_process, err_connection); + const epid* gleader = NULL); /// Attempt to kill a remote process by sending /// an exit message to a_pid, with reason \a a_reason void send_exit(const epid& a_from, const epid& a_to, - const eterm& a_reason) throw (err_no_process, err_connection); + const eterm& a_reason); /// Attempt to kill a remote process by sending /// an exit2 message to a_pid, with reason \a a_reason void send_exit2(const epid& a_from, const epid& a_to, - const eterm& a_reason) throw (err_no_process, err_connection); + const eterm& a_reason); /// Link mailbox to the given pid. /// The given pid will receive an exit message when \a a_pid dies. /// @throws err_no_process /// @throws err_connection - void send_link(const epid& a_from, const epid& a_to) - throw (err_no_process, err_connection); + void send_link(const epid& a_from, const epid& a_to); /// UnLink the given pid - void send_unlink(const epid& a_from, const epid& a_to) - throw (err_no_process, err_connection); + void send_unlink(const epid& a_from, const epid& a_to); const ref& - send_monitor(const epid& a_from, const epid& a_to_pid) - throw (err_no_process, err_connection); + send_monitor(const epid& a_from, const epid& a_to_pid); /// Demonitor the \a a_to pid monitored by \a a_from pid using \a a_ref reference. - void send_demonitor(const epid& a_from, const epid& a_to, const ref& a_ref) - throw (err_no_process, err_connection); + void send_demonitor(const epid& a_from, const epid& a_to, const ref& a_ref); void send_monitor_exit(const epid& a_from, const epid& a_to, - const ref& a_ref, const eterm& a_reason) - throw (err_no_process, err_connection); + const ref& a_ref, const eterm& a_reason); }; diff --git a/include/eixx/connect/basic_otp_node.hxx b/include/eixx/connect/basic_otp_node.hxx index 87a2368..754fccd 100644 --- a/include/eixx/connect/basic_otp_node.hxx +++ b/include/eixx/connect/basic_otp_node.hxx @@ -75,7 +75,6 @@ basic_otp_node( boost::asio::io_service& a_io_svc, const std::string& a_nodename, const std::string& a_cookie, const Alloc& a_alloc, int8_t a_creation) - throw (err_bad_argument, err_connection, eterm_exception) : basic_otp_node_local(a_nodename, a_cookie) , m_creation((a_creation < 0 ? time(NULL) : (int)a_creation) & 0x03) , m_pid_count(1) @@ -190,7 +189,6 @@ template template inline void basic_otp_node:: connect(CompletionHandler h, const atom& a_remote_nodename, size_t a_reconnect_secs) - throw(err_connection) { connect(h, a_remote_nodename, atom(), a_reconnect_secs); } @@ -210,7 +208,7 @@ template template void basic_otp_node:: connect(CompletionHandler h, const atom& a_remote_node, const atom& a_cookie, - size_t a_reconnect_secs) throw(err_connection) + size_t a_reconnect_secs) { lock_guard guard(m_lock); typename conn_hash_map::iterator it = m_connections.find(a_remote_node); @@ -251,20 +249,20 @@ rpc_call(const epid& a_from, const ref& a_ref, template void basic_otp_node:: -publish_port() throw (err_connection) +publish_port() { throw err_connection("Not implemented!"); } template void basic_otp_node:: -unpublish_port() throw (err_connection) +unpublish_port() { throw std::runtime_error("Not implemented"); } template -void basic_otp_node::start_server() throw(err_connection) +void basic_otp_node::start_server() { throw std::runtime_error("Not implemented"); } @@ -289,7 +287,6 @@ report_status(report_level a_level, const connection_t* a_con, const std::string template void basic_otp_node:: deliver(const transport_msg& a_msg) - throw (err_bad_argument, err_no_process, err_connection) { try { const eterm& l_to = a_msg.recipient(); @@ -307,7 +304,6 @@ template template void basic_otp_node:: send(const atom& a_to_node, ToProc a_to, const transport_msg& a_msg) - throw (err_no_process, err_connection) { if (a_to_node == nodename()) { basic_otp_mailbox* mbox = m_mailboxes.get(a_to); @@ -323,7 +319,6 @@ send(const atom& a_to_node, ToProc a_to, const transport_msg& a_msg) template void inline basic_otp_node:: send(const epid& a_to, const eterm& a_msg) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_send(a_to, a_msg, m_allocator); @@ -333,7 +328,6 @@ send(const epid& a_to, const eterm& a_msg) template void inline basic_otp_node:: send(const atom& a_node, const epid& a_to, const eterm& a_msg) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_send(a_to, a_msg, m_allocator); @@ -343,7 +337,6 @@ send(const atom& a_node, const epid& a_to, const eterm& a_msg) template void inline basic_otp_node:: send(const epid& a_from, const atom& a_to, const eterm& a_msg) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_reg_send(a_from, a_to, a_msg, m_allocator); @@ -353,7 +346,6 @@ send(const epid& a_from, const atom& a_to, const eterm& a_msg) template void inline basic_otp_node:: send(const epid& a_from, const atom& a_to_node, const atom& a_to, const eterm& a_msg) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_reg_send(a_from, a_to, a_msg, m_allocator); @@ -365,7 +357,6 @@ void inline basic_otp_node:: send_rpc(const epid& a_from, const atom& a_node, const atom& a_mod, const atom& a_fun, const list& args, const epid* gleader) - throw (err_bad_argument, err_no_process, err_connection) { static const atom rex("rex"); transport_msg tm; @@ -378,7 +369,6 @@ void inline basic_otp_node:: send_rpc_cast(const epid& a_from, const atom& a_node, const atom& a_mod, const atom& a_fun, const list& args, const epid* gleader) - throw (err_bad_argument, err_no_process, err_connection) { static const atom rex("rex"); transport_msg tm; @@ -390,7 +380,6 @@ template void inline basic_otp_node:: send_exit(const epid& a_from, const epid& a_to, const eterm& a_reason) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_exit(a_from, a_to, a_reason, m_allocator); @@ -401,7 +390,6 @@ template void inline basic_otp_node:: send_exit2(const epid& a_from, const epid& a_to, const eterm& a_reason) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_exit2(a_from, a_to, a_reason, m_allocator); @@ -411,7 +399,6 @@ send_exit2(const epid& a_from, const epid& a_to, template void basic_otp_node:: send_link(const epid& a_from, const epid& a_to) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_link(a_from, a_to, m_allocator); @@ -421,7 +408,6 @@ send_link(const epid& a_from, const epid& a_to) template void basic_otp_node:: send_unlink(const epid& a_from, const epid& a_to) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_unlink(a_from, a_to, m_allocator); @@ -431,7 +417,6 @@ send_unlink(const epid& a_from, const epid& a_to) template const ref& basic_otp_node:: send_monitor(const epid& a_from, const epid& a_to) - throw (err_no_process, err_connection) { transport_msg tm; ref r = create_ref(); @@ -444,7 +429,6 @@ template void basic_otp_node:: send_demonitor(const epid& a_from, const epid& a_to, const ref& a_ref) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_demonitor(a_from, a_to, a_ref, m_allocator); @@ -455,7 +439,6 @@ template void basic_otp_node:: send_monitor_exit(const epid& a_from, const epid& a_to, const ref& a_ref, const eterm& a_reason) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_monitor_exit(a_from, a_to, a_ref, a_reason, m_allocator); diff --git a/include/eixx/connect/basic_otp_node_local.hpp b/include/eixx/connect/basic_otp_node_local.hpp index e68be37..dcf5aa9 100644 --- a/include/eixx/connect/basic_otp_node_local.hpp +++ b/include/eixx/connect/basic_otp_node_local.hpp @@ -48,14 +48,12 @@ using marshal::atom; class basic_otp_node_local { public: basic_otp_node_local() {} - basic_otp_node_local(const std::string& a_nodename, const std::string& a_cookie = "") - throw (std::runtime_error, err_bad_argument); + basic_otp_node_local(const std::string& a_nodename, const std::string& a_cookie = ""); virtual ~basic_otp_node_local() {} /// Change the nodename of current node. - void set_nodename(const std::string& a_nodename, const std::string& a_cookie = "") - throw (std::runtime_error, err_bad_argument); + void set_nodename(const std::string& a_nodename, const std::string& a_cookie = ""); /// Get node name in the form node@host. atom nodename() const { return m_nodename; } diff --git a/include/eixx/connect/transport_msg.hpp b/include/eixx/connect/transport_msg.hpp index 5bb80fa..a316ebf 100644 --- a/include/eixx/connect/transport_msg.hpp +++ b/include/eixx/connect/transport_msg.hpp @@ -144,7 +144,8 @@ class transport_msg { /// This function may only raise exception for MONITOR_P_EXIT /// message types if the message sender is given by name rather than by pid. - const epid& sender_pid() const throw (err_wrong_type) { + /// @throw err_wrong_type + const epid& sender_pid() const { return sender().to_pid(); } @@ -177,15 +178,18 @@ class transport_msg { /// This function may only raise exception for MONITOR_P|DEMONITOR_P /// message types if the message sender is given by name rather than by pid. - const epid& recipient_pid() const throw (err_wrong_type) { + /// @throw err_wrong_type + const epid& recipient_pid() const { return recipient().to_pid(); } - const atom& recipient_name() const throw (err_wrong_type) { + /// @throw err_wrong_type + const atom& recipient_name() const { return recipient().to_atom(); } - const eterm& trace_token() const throw (err_wrong_type) { + /// @throw err_wrong_type + const eterm& trace_token() const { switch (m_type) { case SEND_TT: case EXIT_TT: @@ -196,7 +200,8 @@ class transport_msg { } } - const ref& get_ref() const throw (err_wrong_type) { + /// @throw err_wrong_type + const ref& get_ref() const { switch (m_type) { case MONITOR_P: case DEMONITOR_P: @@ -207,7 +212,8 @@ class transport_msg { } } - const eterm& reason() const throw (err_wrong_type) { + /// @throw err_wrong_type + const eterm& reason() const { switch (m_type) { case EXIT: case EXIT2: return m_cntrl[3]; diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index e178881..a9c43fd 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -182,8 +182,7 @@ class connection /// Note: TICK message is represented by msg type = 0, in this case \a a_cntrl_msg /// and \a a_msg are invalid. /// @return Control Message - int transport_msg_decode(const char *mbuf, int len, transport_msg& a_tm) - throw(err_decode_exception); + int transport_msg_decode(const char *mbuf, int len, transport_msg& a_tm); void process_message(const char* a_buf, size_t a_size); @@ -225,8 +224,7 @@ class connection /// modified to exclude the "...://" prefix. /// @param is a connection address (e.g. "tcp://node@host"). /// @return connection type derived from s. - static connection_type parse_connection_type(std::string& s) - throw(std::runtime_error); + static connection_type parse_connection_type(std::string& s); /// Establish connection to \a a_remote_nodename. The call is non-blocking - /// it will immediately returned, and Handler's on_connect() or @@ -235,7 +233,6 @@ class connection virtual void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie) - throw(std::runtime_error) { m_this_node = a_this_node; m_remote_nodename = a_remote_nodename; diff --git a/include/eixx/connect/transport_otp_connection.hxx b/include/eixx/connect/transport_otp_connection.hxx index da505fb..6135519 100644 --- a/include/eixx/connect/transport_otp_connection.hxx +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -92,7 +92,7 @@ connection::create( template connection_type -connection::parse_connection_type(std::string& s) throw(std::runtime_error) +connection::parse_connection_type(std::string& s) { size_t pos = s.find("://", 0); if (pos == std::string::npos) @@ -352,7 +352,6 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) template int connection:: transport_msg_decode(const char *mbuf, int len, transport_msg& a_tm) - throw(err_decode_exception) { const char* s = mbuf; int version; diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index fa333e8..2c6a90c 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -148,8 +148,7 @@ class tcp_connection uint32_t m_remote_challenge; uint32_t m_our_challenge; - void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie) - throw(std::runtime_error); + void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie); boost::shared_ptr > shared_from_this() { boost::shared_ptr > p = base_t::shared_from_this(); diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index 4f06b21..73aebf7 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -54,7 +54,7 @@ void tcp_connection::start() template void tcp_connection::connect( - atom a_this_node, atom a_remote_node, atom a_cookie) throw(std::runtime_error) + atom a_this_node, atom a_remote_node, atom a_cookie) { using boost::asio::ip::tcp; diff --git a/include/eixx/connect/transport_otp_connection_uds.hpp b/include/eixx/connect/transport_otp_connection_uds.hpp index 17da638..42493e6 100644 --- a/include/eixx/connect/transport_otp_connection_uds.hpp +++ b/include/eixx/connect/transport_otp_connection_uds.hpp @@ -88,7 +88,6 @@ class uds_connection std::string m_uds_filename; void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie) - throw(std::runtime_error) { base_t::connect(a_this_node, a_remote_nodename, a_cookie); From 50be339893e487505b54690433bfef2de3b2ad0c Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Tue, 17 Aug 2021 02:46:55 +0800 Subject: [PATCH 159/185] fix C++17 warnings --- include/eixx/connect/basic_otp_connection.hpp | 3 +- include/eixx/connect/basic_otp_mailbox.hpp | 20 +++-- include/eixx/connect/basic_otp_mailbox.hxx | 4 +- .../connect/basic_otp_mailbox_registry.hpp | 10 ++- .../connect/basic_otp_mailbox_registry.hxx | 9 +- include/eixx/connect/basic_otp_node.hpp | 88 +++++++++++-------- include/eixx/connect/basic_otp_node.hxx | 25 +----- include/eixx/connect/basic_otp_node_local.hpp | 11 ++- include/eixx/connect/transport_msg.hpp | 18 ++-- .../eixx/connect/transport_otp_connection.hpp | 10 +-- .../eixx/connect/transport_otp_connection.hxx | 4 +- .../connect/transport_otp_connection_tcp.hpp | 4 +- .../connect/transport_otp_connection_tcp.hxx | 2 +- .../connect/transport_otp_connection_uds.hpp | 2 +- src/basic_otp_node_local.cpp | 2 - 15 files changed, 116 insertions(+), 96 deletions(-) diff --git a/include/eixx/connect/basic_otp_connection.hpp b/include/eixx/connect/basic_otp_connection.hpp index 2d74539..023ada3 100644 --- a/include/eixx/connect/basic_otp_connection.hpp +++ b/include/eixx/connect/basic_otp_connection.hpp @@ -152,7 +152,8 @@ class basic_otp_connection m_transport->stop(); } - void send(const transport_msg& a_msg) throw (err_connection) { + /// @throws err_connection if not connected to \a a_node._ + void send(const transport_msg& a_msg) { if (!m_transport) { if (m_abort) return; diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index 591afc9..ee44c0f 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -200,6 +200,7 @@ class basic_otp_mailbox * @param a_timeout is the timeout interval to wait for message (-1 = infinity) * @param a_repeat_count is the number of messages to wait (-1 = infinite) * @return true if the message was synchronously received + * @throws std::runtime_error **/ template bool async_receive @@ -207,8 +208,7 @@ class basic_otp_mailbox const OnReceive& h, std::chrono::milliseconds a_timeout = std::chrono::milliseconds(-1), int a_repeat_count = 0 - ) - throw (std::runtime_error); + ); /** * Cancel pending asynchronous receive operation @@ -227,6 +227,7 @@ class basic_otp_mailbox * void on_timeout(basic_otp_mailbox&); * \endcode * @param a_repeat_count number of messages to wait (-1 = infinite) + * @throws std::runtime_error */ template bool async_match @@ -235,8 +236,7 @@ class basic_otp_mailbox const OnTimeout& a_on_timeout, std::chrono::milliseconds a_timeout = std::chrono::milliseconds(-1), int a_repeat_count = 0 - ) - throw (std::runtime_error); + ); /// Deliver a message to this mailbox. The call is thread-safe. void deliver(const transport_msg& a_msg) { @@ -294,11 +294,15 @@ class basic_otp_mailbox m_node.send_rpc(self(), a_node, a_mod, a_fun, args); } - /// Execute an equivalent of rpc:cast(...). Doesn't return any value. + /** + * Execute an equivalent of rpc:cast(...). Doesn't return any value. + * @throws err_bad_argument + * @throws err_no_process + * @throws err_connection + */ void send_rpc_cast(const atom& a_node, const atom& a_mod, const atom& a_fun, const list& args, - const epid* gleader = NULL) - throw (err_bad_argument, err_no_process, err_connection) { + const epid* gleader = NULL) { m_node.send_rpc_cast(self(), a_node, a_mod, a_fun, args, gleader); } @@ -315,7 +319,7 @@ class basic_otp_mailbox /// The given pid will receive an exit message when \a a_pid dies. /// @throws err_no_process /// @throws err_connection - void link(const epid& a_to) throw (err_no_process, err_connection) { + void link(const epid& a_to) { if (self() == a_to) return; if (m_links.find(a_to) != m_links.end()) diff --git a/include/eixx/connect/basic_otp_mailbox.hxx b/include/eixx/connect/basic_otp_mailbox.hxx index 8dfa6fe..62eee4b 100644 --- a/include/eixx/connect/basic_otp_mailbox.hxx +++ b/include/eixx/connect/basic_otp_mailbox.hxx @@ -51,7 +51,7 @@ template template bool basic_otp_mailbox:: async_receive(const OnReceive& h, std::chrono::milliseconds a_timeout, - int a_repeat_count) throw (std::runtime_error) + int a_repeat_count) { return m_queue->async_dequeue( [this, &h](transport_msg*& a_msg, const boost::system::error_code& ec) { @@ -81,7 +81,7 @@ bool basic_otp_mailbox:: async_match(const marshal::eterm_pattern_matcher& a_matcher, const OnTimeout& a_on_timeout, std::chrono::milliseconds a_timeout, - int a_repeat_count) throw (std::runtime_error) + int a_repeat_count) { auto f = [this, &a_matcher, &a_on_timeout] diff --git a/include/eixx/connect/basic_otp_mailbox_registry.hpp b/include/eixx/connect/basic_otp_mailbox_registry.hpp index 7a3e756..985c7cd 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.hpp +++ b/include/eixx/connect/basic_otp_mailbox_registry.hpp @@ -81,25 +81,29 @@ struct basic_otp_mailbox_registry { /** * Look up a mailbox based on its name or pid. + * @throws err_bad_argument + * @throws err_no_process */ mailbox_ptr - get(const eterm& a_proc) const throw (err_bad_argument, err_no_process); + get(const eterm& a_proc) const; /** * Look up a mailbox based on its name. If the mailbox has gone out * of scope we also remove the reference from the hashtable so we * don't find it again. + * @throws err_no_process */ mailbox_ptr - get(atom a_name) const throw(err_no_process); + get(atom a_name) const; /** * Look up a mailbox based on its pid. If the mailbox has gone out * of scope we also remove the reference from the hashtable so we * don't find it again. + * @throws err_no_process */ mailbox_ptr - get(const epid& a_pid) const throw(err_no_process); + get(const epid& a_pid) const; void names(std::list& list); diff --git a/include/eixx/connect/basic_otp_mailbox_registry.hxx b/include/eixx/connect/basic_otp_mailbox_registry.hxx index 14d8017..663dcf1 100644 --- a/include/eixx/connect/basic_otp_mailbox_registry.hxx +++ b/include/eixx/connect/basic_otp_mailbox_registry.hxx @@ -153,11 +153,13 @@ erase(mailbox_ptr a_mbox) /** * Look up a mailbox based on its name or pid. + * @throws err_bad_argument + * @throws err_no_process */ template typename basic_otp_mailbox_registry::mailbox_ptr basic_otp_mailbox_registry:: -get(const eterm& a_proc) const throw (err_bad_argument, err_no_process) +get(const eterm& a_proc) const { switch (a_proc.type()) { case ATOM: return get(a_proc.to_atom()); @@ -170,11 +172,12 @@ get(const eterm& a_proc) const throw (err_bad_argument, err_no_process) * Look up a mailbox based on its name. If the mailbox has gone out * of scope we also remove the reference from the hashtable so we * don't find it again. + * @throws err_no_process */ template typename basic_otp_mailbox_registry::mailbox_ptr basic_otp_mailbox_registry:: -get(atom a_name) const throw(err_no_process) +get(atom a_name) const { lock_guard guard(m_lock); typename std::map::iterator it = m_by_name.find(a_name); @@ -187,11 +190,11 @@ get(atom a_name) const throw(err_no_process) * Look up a mailbox based on its pid. If the mailbox has gone out * of scope we also remove the reference from the hashtable so we * don't find it again. + * @throws err_no_process */ template typename basic_otp_mailbox_registry::mailbox_ptr basic_otp_mailbox_registry::get(const epid& a_pid) const - throw(err_no_process) { lock_guard guard(m_lock); typename std::map, mailbox_ptr>::iterator it = m_by_pid.find(a_pid); diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index c49b98b..3abacda 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -107,17 +107,20 @@ class basic_otp_node: public basic_otp_node_local { protected: /// Publish the node port to epmd making this node known to the world. - void publish_port() throw (err_connection); + /// @throws err_connection + void publish_port(); /// Unregister this node from epmd. - void unpublish_port() throw (err_connection); + /// @throws err_connection + void unpublish_port(); /// Send a message to a process ToProc which is either epid or /// atom for registered names. + /// @throws err_no_process + /// @throws err_connection template void send(const atom& a_to_node, - ToProc a_to, const transport_msg& a_msg) - throw (err_no_process, err_connection); + ToProc a_to, const transport_msg& a_msg); public: typedef basic_otp_mailbox_registry mailbox_registry_t; @@ -140,8 +143,7 @@ class basic_otp_node: public basic_otp_node_local { const std::string& a_nodename = std::string(), const std::string& a_cookie = std::string(), const Alloc& a_alloc = Alloc(), - int8_t a_creation = -1) - throw (err_bad_argument, err_connection, eterm_exception); + int8_t a_creation = -1); virtual ~basic_otp_node() { close(); } @@ -220,11 +222,11 @@ class basic_otp_node: public basic_otp_node_local { * attempts in case of connection drops. * @returns A new connection. The connection has no receiver defined * and is not started. + * @throws err_connection */ template void connect(CompletionHandler h, const atom& a_remote_node, - const atom& a_cookie = atom(), size_t a_reconnect_secs = 0) - throw(err_connection); + const atom& a_cookie = atom(), size_t a_reconnect_secs = 0); /** * Set up a connection to an Erlang node, using default cookie @@ -233,10 +235,11 @@ class basic_otp_node: public basic_otp_node_local { * attempts in case of connection drops. * @returns A new connection. The connection has no receiver defined * and is not started. + * @throws err_connection */ template void connect(CompletionHandler h, const atom& a_remote_nodename, - size_t a_reconnect_secs = 0) throw(err_connection); + size_t a_reconnect_secs = 0); /// Get connection identified by the \a a_node name. /// @throws err_connection if not connected to \a a_node._ @@ -270,7 +273,7 @@ class basic_otp_node: public basic_otp_node_local { * registers the port with local epmd daemon. * @throws err_connection if cannot connect to epmd. */ - void start_server() throw(err_connection); + void start_server(); /** * Stop accepting connections from client processes. @@ -280,31 +283,38 @@ class basic_otp_node: public basic_otp_node_local { void stop_server(); /// Deliver a message to its local receipient mailbox. - void deliver(const transport_msg& a_tm) - throw (err_bad_argument, err_no_process, err_connection); + /// @throws err_bad_argument + /// @throws err_no_process + /// @throws err_connection + void deliver(const transport_msg& a_tm); /// Send a message \a a_msg from \a a_from pid to \a a_to pid. /// @param a_to is a remote process. /// @param a_msg is the message to send. - void send(const epid& a_to, const eterm& a_msg) - throw (err_no_process, err_connection); + /// @throws err_no_process + /// @throws err_connection + void send(const epid& a_to, const eterm& a_msg); /// Send a message \a a_msg to the remote process \a a_to on node \a a_node. /// The remote process \a a_to need not belong to node \a a_node. /// @param a_node is the node to send the message to. /// @param a_to is a remote process. /// @param a_msg is the message to send. - void send(const atom& a_node, const epid& a_to, const eterm& a_msg) - throw (err_no_process, err_connection); + /// @throws err_no_process + /// @throws err_connection + void send(const atom& a_node, const epid& a_to, const eterm& a_msg); /// Send a message \a a_msg to the local process registered as \a a_to. - void send(const epid& a_from, const atom& a_to, const eterm& a_msg) - throw (err_no_process, err_connection); + /// @throws err_no_process + /// @throws err_connection + void send(const epid& a_from, const atom& a_to, const eterm& a_msg); /// Send a message \a a_msg to the process registered as \a a_to_name /// on remote node \a a_node. + /// @throws err_no_process + /// @throws err_connection void send(const epid& a_from, const atom& a_to_node, const atom& a_to_name, - const eterm& a_msg) throw (err_no_process, err_connection); + const eterm& a_msg); /** * Send an RPC request to a remote Erlang node. @@ -323,47 +333,55 @@ class basic_otp_node: public basic_otp_node_local { */ void send_rpc(const epid& a_from, const atom& a_to_node, const atom& a_mod, const atom& a_fun, const list& args, - const epid* gleader = NULL) - throw (err_bad_argument, err_no_process, err_connection); + const epid* gleader = NULL); /// Execute an equivalent of rpc:cast(...). Doesn't return any value. + /// @throws err_bad_argument + /// @throws err_no_process + /// @throws err_connection void send_rpc_cast(const epid& a_from, const atom& a_to_node, const atom& a_mod, const atom& a_fun, const list& args, - const epid* gleader = NULL) - throw (err_bad_argument, err_no_process, err_connection); + const epid* gleader = NULL); /// Attempt to kill a remote process by sending /// an exit message to a_pid, with reason \a a_reason + /// @throws err_no_process + /// @throws err_connection void send_exit(const epid& a_from, const epid& a_to, - const eterm& a_reason) throw (err_no_process, err_connection); + const eterm& a_reason); /// Attempt to kill a remote process by sending /// an exit2 message to a_pid, with reason \a a_reason + /// @throws err_no_process + /// @throws err_connection void send_exit2(const epid& a_from, const epid& a_to, - const eterm& a_reason) throw (err_no_process, err_connection); + const eterm& a_reason); /// Link mailbox to the given pid. /// The given pid will receive an exit message when \a a_pid dies. /// @throws err_no_process /// @throws err_connection - void send_link(const epid& a_from, const epid& a_to) - throw (err_no_process, err_connection); + void send_link(const epid& a_from, const epid& a_to); /// UnLink the given pid - void send_unlink(const epid& a_from, const epid& a_to) - throw (err_no_process, err_connection); + /// @throws err_no_process + /// @throws err_connection + void send_unlink(const epid& a_from, const epid& a_to); + /// @throws err_no_process + /// @throws err_connection const ref& - send_monitor(const epid& a_from, const epid& a_to_pid) - throw (err_no_process, err_connection); + send_monitor(const epid& a_from, const epid& a_to_pid); /// Demonitor the \a a_to pid monitored by \a a_from pid using \a a_ref reference. - void send_demonitor(const epid& a_from, const epid& a_to, const ref& a_ref) - throw (err_no_process, err_connection); + /// @throws err_no_process + /// @throws err_connection + void send_demonitor(const epid& a_from, const epid& a_to, const ref& a_ref); + /// @throws err_no_process + /// @throws err_connection void send_monitor_exit(const epid& a_from, const epid& a_to, - const ref& a_ref, const eterm& a_reason) - throw (err_no_process, err_connection); + const ref& a_ref, const eterm& a_reason); }; diff --git a/include/eixx/connect/basic_otp_node.hxx b/include/eixx/connect/basic_otp_node.hxx index 87a2368..754fccd 100644 --- a/include/eixx/connect/basic_otp_node.hxx +++ b/include/eixx/connect/basic_otp_node.hxx @@ -75,7 +75,6 @@ basic_otp_node( boost::asio::io_service& a_io_svc, const std::string& a_nodename, const std::string& a_cookie, const Alloc& a_alloc, int8_t a_creation) - throw (err_bad_argument, err_connection, eterm_exception) : basic_otp_node_local(a_nodename, a_cookie) , m_creation((a_creation < 0 ? time(NULL) : (int)a_creation) & 0x03) , m_pid_count(1) @@ -190,7 +189,6 @@ template template inline void basic_otp_node:: connect(CompletionHandler h, const atom& a_remote_nodename, size_t a_reconnect_secs) - throw(err_connection) { connect(h, a_remote_nodename, atom(), a_reconnect_secs); } @@ -210,7 +208,7 @@ template template void basic_otp_node:: connect(CompletionHandler h, const atom& a_remote_node, const atom& a_cookie, - size_t a_reconnect_secs) throw(err_connection) + size_t a_reconnect_secs) { lock_guard guard(m_lock); typename conn_hash_map::iterator it = m_connections.find(a_remote_node); @@ -251,20 +249,20 @@ rpc_call(const epid& a_from, const ref& a_ref, template void basic_otp_node:: -publish_port() throw (err_connection) +publish_port() { throw err_connection("Not implemented!"); } template void basic_otp_node:: -unpublish_port() throw (err_connection) +unpublish_port() { throw std::runtime_error("Not implemented"); } template -void basic_otp_node::start_server() throw(err_connection) +void basic_otp_node::start_server() { throw std::runtime_error("Not implemented"); } @@ -289,7 +287,6 @@ report_status(report_level a_level, const connection_t* a_con, const std::string template void basic_otp_node:: deliver(const transport_msg& a_msg) - throw (err_bad_argument, err_no_process, err_connection) { try { const eterm& l_to = a_msg.recipient(); @@ -307,7 +304,6 @@ template template void basic_otp_node:: send(const atom& a_to_node, ToProc a_to, const transport_msg& a_msg) - throw (err_no_process, err_connection) { if (a_to_node == nodename()) { basic_otp_mailbox* mbox = m_mailboxes.get(a_to); @@ -323,7 +319,6 @@ send(const atom& a_to_node, ToProc a_to, const transport_msg& a_msg) template void inline basic_otp_node:: send(const epid& a_to, const eterm& a_msg) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_send(a_to, a_msg, m_allocator); @@ -333,7 +328,6 @@ send(const epid& a_to, const eterm& a_msg) template void inline basic_otp_node:: send(const atom& a_node, const epid& a_to, const eterm& a_msg) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_send(a_to, a_msg, m_allocator); @@ -343,7 +337,6 @@ send(const atom& a_node, const epid& a_to, const eterm& a_msg) template void inline basic_otp_node:: send(const epid& a_from, const atom& a_to, const eterm& a_msg) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_reg_send(a_from, a_to, a_msg, m_allocator); @@ -353,7 +346,6 @@ send(const epid& a_from, const atom& a_to, const eterm& a_msg) template void inline basic_otp_node:: send(const epid& a_from, const atom& a_to_node, const atom& a_to, const eterm& a_msg) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_reg_send(a_from, a_to, a_msg, m_allocator); @@ -365,7 +357,6 @@ void inline basic_otp_node:: send_rpc(const epid& a_from, const atom& a_node, const atom& a_mod, const atom& a_fun, const list& args, const epid* gleader) - throw (err_bad_argument, err_no_process, err_connection) { static const atom rex("rex"); transport_msg tm; @@ -378,7 +369,6 @@ void inline basic_otp_node:: send_rpc_cast(const epid& a_from, const atom& a_node, const atom& a_mod, const atom& a_fun, const list& args, const epid* gleader) - throw (err_bad_argument, err_no_process, err_connection) { static const atom rex("rex"); transport_msg tm; @@ -390,7 +380,6 @@ template void inline basic_otp_node:: send_exit(const epid& a_from, const epid& a_to, const eterm& a_reason) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_exit(a_from, a_to, a_reason, m_allocator); @@ -401,7 +390,6 @@ template void inline basic_otp_node:: send_exit2(const epid& a_from, const epid& a_to, const eterm& a_reason) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_exit2(a_from, a_to, a_reason, m_allocator); @@ -411,7 +399,6 @@ send_exit2(const epid& a_from, const epid& a_to, template void basic_otp_node:: send_link(const epid& a_from, const epid& a_to) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_link(a_from, a_to, m_allocator); @@ -421,7 +408,6 @@ send_link(const epid& a_from, const epid& a_to) template void basic_otp_node:: send_unlink(const epid& a_from, const epid& a_to) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_unlink(a_from, a_to, m_allocator); @@ -431,7 +417,6 @@ send_unlink(const epid& a_from, const epid& a_to) template const ref& basic_otp_node:: send_monitor(const epid& a_from, const epid& a_to) - throw (err_no_process, err_connection) { transport_msg tm; ref r = create_ref(); @@ -444,7 +429,6 @@ template void basic_otp_node:: send_demonitor(const epid& a_from, const epid& a_to, const ref& a_ref) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_demonitor(a_from, a_to, a_ref, m_allocator); @@ -455,7 +439,6 @@ template void basic_otp_node:: send_monitor_exit(const epid& a_from, const epid& a_to, const ref& a_ref, const eterm& a_reason) - throw (err_no_process, err_connection) { transport_msg tm; tm.set_monitor_exit(a_from, a_to, a_ref, a_reason, m_allocator); diff --git a/include/eixx/connect/basic_otp_node_local.hpp b/include/eixx/connect/basic_otp_node_local.hpp index e68be37..66e84bc 100644 --- a/include/eixx/connect/basic_otp_node_local.hpp +++ b/include/eixx/connect/basic_otp_node_local.hpp @@ -48,14 +48,17 @@ using marshal::atom; class basic_otp_node_local { public: basic_otp_node_local() {} - basic_otp_node_local(const std::string& a_nodename, const std::string& a_cookie = "") - throw (std::runtime_error, err_bad_argument); + + /// @throws std::runtime_error + /// @throws err_bad_argument + basic_otp_node_local(const std::string& a_nodename, const std::string& a_cookie = ""); virtual ~basic_otp_node_local() {} /// Change the nodename of current node. - void set_nodename(const std::string& a_nodename, const std::string& a_cookie = "") - throw (std::runtime_error, err_bad_argument); + /// @throws std::runtime_error + /// @throws err_bad_argument + void set_nodename(const std::string& a_nodename, const std::string& a_cookie = ""); /// Get node name in the form node@host. atom nodename() const { return m_nodename; } diff --git a/include/eixx/connect/transport_msg.hpp b/include/eixx/connect/transport_msg.hpp index 5bb80fa..0c47598 100644 --- a/include/eixx/connect/transport_msg.hpp +++ b/include/eixx/connect/transport_msg.hpp @@ -144,7 +144,8 @@ class transport_msg { /// This function may only raise exception for MONITOR_P_EXIT /// message types if the message sender is given by name rather than by pid. - const epid& sender_pid() const throw (err_wrong_type) { + /// @throws err_wrong_type + const epid& sender_pid() const { return sender().to_pid(); } @@ -177,15 +178,18 @@ class transport_msg { /// This function may only raise exception for MONITOR_P|DEMONITOR_P /// message types if the message sender is given by name rather than by pid. - const epid& recipient_pid() const throw (err_wrong_type) { + /// @throws err_wrong_type + const epid& recipient_pid() const { return recipient().to_pid(); } - const atom& recipient_name() const throw (err_wrong_type) { + /// @throws err_wrong_type + const atom& recipient_name() const { return recipient().to_atom(); } - const eterm& trace_token() const throw (err_wrong_type) { + /// @throws err_wrong_type + const eterm& trace_token() const { switch (m_type) { case SEND_TT: case EXIT_TT: @@ -196,7 +200,8 @@ class transport_msg { } } - const ref& get_ref() const throw (err_wrong_type) { + /// @throws err_wrong_type + const ref& get_ref() const { switch (m_type) { case MONITOR_P: case DEMONITOR_P: @@ -207,7 +212,8 @@ class transport_msg { } } - const eterm& reason() const throw (err_wrong_type) { + /// @throws err_wrong_type + const eterm& reason() const { switch (m_type) { case EXIT: case EXIT2: return m_cntrl[3]; diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index e178881..c765704 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -182,8 +182,8 @@ class connection /// Note: TICK message is represented by msg type = 0, in this case \a a_cntrl_msg /// and \a a_msg are invalid. /// @return Control Message - int transport_msg_decode(const char *mbuf, int len, transport_msg& a_tm) - throw(err_decode_exception); + /// @throws err_decode_exception + int transport_msg_decode(const char *mbuf, int len, transport_msg& a_tm); void process_message(const char* a_buf, size_t a_size); @@ -225,17 +225,17 @@ class connection /// modified to exclude the "...://" prefix. /// @param is a connection address (e.g. "tcp://node@host"). /// @return connection type derived from s. - static connection_type parse_connection_type(std::string& s) - throw(std::runtime_error); + /// @throws std::runtime_error + static connection_type parse_connection_type(std::string& s); /// Establish connection to \a a_remote_nodename. The call is non-blocking - /// it will immediately returned, and Handler's on_connect() or /// on_error() callback will be invoked on successful/failed connection /// status. + /// @throws std::runtime_error virtual void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie) - throw(std::runtime_error) { m_this_node = a_this_node; m_remote_nodename = a_remote_nodename; diff --git a/include/eixx/connect/transport_otp_connection.hxx b/include/eixx/connect/transport_otp_connection.hxx index da505fb..903cfa5 100644 --- a/include/eixx/connect/transport_otp_connection.hxx +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -92,7 +92,7 @@ connection::create( template connection_type -connection::parse_connection_type(std::string& s) throw(std::runtime_error) +connection::parse_connection_type(std::string& s) { size_t pos = s.find("://", 0); if (pos == std::string::npos) @@ -349,10 +349,10 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) /// Note: TICK message is represented by msg type = 0, in this case \a a_cntrl_msg /// and \a a_msg are invalid. /// @return message type +/// @throws err_decode_exception template int connection:: transport_msg_decode(const char *mbuf, int len, transport_msg& a_tm) - throw(err_decode_exception) { const char* s = mbuf; int version; diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index fa333e8..8899b51 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -148,8 +148,8 @@ class tcp_connection uint32_t m_remote_challenge; uint32_t m_our_challenge; - void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie) - throw(std::runtime_error); + /// @throws std::runtime_error + void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie); boost::shared_ptr > shared_from_this() { boost::shared_ptr > p = base_t::shared_from_this(); diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index 4f06b21..73aebf7 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -54,7 +54,7 @@ void tcp_connection::start() template void tcp_connection::connect( - atom a_this_node, atom a_remote_node, atom a_cookie) throw(std::runtime_error) + atom a_this_node, atom a_remote_node, atom a_cookie) { using boost::asio::ip::tcp; diff --git a/include/eixx/connect/transport_otp_connection_uds.hpp b/include/eixx/connect/transport_otp_connection_uds.hpp index 17da638..065d777 100644 --- a/include/eixx/connect/transport_otp_connection_uds.hpp +++ b/include/eixx/connect/transport_otp_connection_uds.hpp @@ -87,8 +87,8 @@ class uds_connection boost::asio::local::stream_protocol::socket m_socket; std::string m_uds_filename; + /// @throws std::runtime_error void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie) - throw(std::runtime_error) { base_t::connect(a_this_node, a_remote_nodename, a_cookie); diff --git a/src/basic_otp_node_local.cpp b/src/basic_otp_node_local.cpp index a6d896c..19c6043 100644 --- a/src/basic_otp_node_local.cpp +++ b/src/basic_otp_node_local.cpp @@ -62,14 +62,12 @@ std::string basic_otp_node_local::s_localhost = boost::asio::ip::host_name( basic_otp_node_local::basic_otp_node_local( const std::string& a_nodename, const std::string& a_cookie) - throw (std::runtime_error, err_bad_argument) { set_nodename(a_nodename, a_cookie); } void basic_otp_node_local::set_nodename( const std::string& a_nodename, const std::string& a_cookie) - throw (std::runtime_error, err_bad_argument) { if (m_cookie.size() > EI_MAX_COOKIE_SIZE) throw err_bad_argument("Cookie size too long", m_cookie.size()); From b5ddb651f90ee5ebdbab2437f3b561d79e035246 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Fri, 20 Aug 2021 13:39:54 -0400 Subject: [PATCH 160/185] Fix miscellaneous issues for connecting to OTP 24.0 node --- CMakeLists.txt | 2 +- .../eixx/connect/transport_otp_connection.hxx | 4 +- .../connect/transport_otp_connection_tcp.hxx | 24 +- include/eixx/eterm_exception.hpp | 20 +- include/eixx/marshal/eterm.hxx | 4 + include/eixx/marshal/pid.hpp | 70 ++- include/eixx/marshal/pid.hxx | 22 +- include/eixx/marshal/port.hpp | 23 +- include/eixx/marshal/port.hxx | 48 +- include/eixx/marshal/ref.hpp | 114 ++-- include/eixx/marshal/ref.hxx | 57 +- src/basic_otp_node_local.cpp | 2 - test/test_eterm.cpp | 518 +++++++++--------- test/test_eterm_encode.cpp | 33 +- 14 files changed, 512 insertions(+), 429 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a947dbd..8a09c87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ project(eixx VERSION 1.4) # CMAKE options customization #=============================================================================== option(VERBOSE "Turn verbosity on|off" OFF) -option(EIXX_MARSHAL_ONLY "Limit build to eterm marshal lib on|off" ON) +option(EIXX_MARSHAL_ONLY "Limit build to eterm marshal lib on|off" OFF) if(VERBOSE) set(CMAKE_VERBOSE_MAKEFILE ON) diff --git a/include/eixx/connect/transport_otp_connection.hxx b/include/eixx/connect/transport_otp_connection.hxx index 6135519..cf56486 100644 --- a/include/eixx/connect/transport_otp_connection.hxx +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -264,7 +264,7 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) << ", length=" << rd_length() << ", rd_buf.size=" << m_rd_buf.capacity() << ", got_header=" << (m_got_header ? "true" : "false") - << ", " << to_binary_string(m_rd_ptr, std::min(rd_length(), 15lu)) << "..." + << ", " << to_binary_string(m_rd_ptr, std::min(rd_length(), 25lu)) << "..." << std::endl; */ @@ -274,7 +274,6 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) m_in_msg_count++; try { - /* if (unlikely(verbose() >= VERBOSE_WIRE)) { std::cout << " MsgCnt=" << m_in_msg_count << ", pkt_size=" << m_packet_size << ", need=" << need_bytes @@ -287,7 +286,6 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) to_binary_string( std::cout << "client <- server: ", m_rd_ptr, m_packet_size) << std::endl; } - */ // Decode the packet into a message and dispatch it. process_message(m_rd_ptr, m_packet_size); diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index 73aebf7..7173735 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -336,18 +336,18 @@ void tcp_connection::handle_connect(const boost::system::error_c put8(w, 'n'); put16be(w, m_dist_version); unsigned int flags = (DFLAG_EXTENDED_REFERENCES - | DFLAG_DIST_MONITOR - | DFLAG_EXTENDED_PIDS_PORTS - | DFLAG_FUN_TAGS - | DFLAG_NEW_FUN_TAGS - | DFLAG_NEW_FLOATS - | DFLAG_SMALL_ATOM_TAGS - | DFLAG_UTF8_ATOMS - | DFLAG_MAP_TAG - // | DFLAG_BIG_CREATION - // | DFLAG_EXPORT_PTR_TAG - // | DFLAG_BIT_BINARIES - ); + | DFLAG_DIST_MONITOR + | DFLAG_EXTENDED_PIDS_PORTS + | DFLAG_FUN_TAGS + | DFLAG_NEW_FUN_TAGS + | DFLAG_NEW_FLOATS + | DFLAG_SMALL_ATOM_TAGS + | DFLAG_UTF8_ATOMS + | DFLAG_MAP_TAG + | DFLAG_BIG_CREATION + | DFLAG_EXPORT_PTR_TAG + | DFLAG_BIT_BINARIES + ); put32be(w, flags); memcpy(w, this->local_nodename().c_str(), this->local_nodename().size()); diff --git a/include/eixx/eterm_exception.hpp b/include/eixx/eterm_exception.hpp index bddefbd..b478648 100644 --- a/include/eixx/eterm_exception.hpp +++ b/include/eixx/eterm_exception.hpp @@ -152,18 +152,23 @@ class err_format_exception: public eterm_exception { */ class err_encode_exception: public eterm_exception { int m_code; + long m_value; std::string m_what; public: - err_encode_exception(const std::string &msg, int code=0) + err_encode_exception(const std::string &msg, int code=0, long value=0) : eterm_exception(msg) , m_code(code) + , m_value(value) { - std::stringstream s; s << m_msg << " (" << m_code << ")."; + std::stringstream s; s << m_msg; + if (value != 0) s << " (" << m_value << ")"; + if (code > -1) s << " at (" << m_code << ")"; m_what = s.str(); } - const char* what() const throw() { return m_what.c_str(); } - int code() const { return m_code; } + const char* what() const throw() { return m_what.c_str(); } + int code() const { return m_code; } + int value() const { return m_value; } }; /** @@ -171,8 +176,11 @@ class err_encode_exception: public eterm_exception { */ class err_decode_exception: public err_encode_exception { public: - err_decode_exception(const std::string &msg, int code=0) - : err_encode_exception(msg, code) + err_decode_exception(const std::string &msg, int pos=0) + : err_encode_exception(msg, pos) + {} + err_decode_exception(const std::string &msg, int pos, long value) + : err_encode_exception(msg, pos, value) {} }; diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index 6f5f5e1..f640aae 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -150,6 +150,10 @@ inline bool eterm::operator== (const eterm& rhs) const { static_assert(MAX_ETERM_TYPE == 14, "Invalid number of terms"); } + + + + template inline bool eterm::operator< (const eterm& rhs) const { /// Term comparison precedence diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index fb811cf..734500a 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -48,32 +48,21 @@ class epid { struct pid_blob { // creation is a special value that allows // distinguishing pid values between successive node restarts. - union u { - struct s { - uint16_t id : 15; - uint16_t serial : 13; - uint8_t creation: 2; - } __attribute__((__packed__)) s; - uint32_t i; - - BOOST_STATIC_ASSERT(sizeof(s) == 4); - - u(int a_id, uint8_t a_cre) { - i = (a_id & 0x0FFFffff) | ((a_cre & 0x3) << 28); - } - - u(uint16_t a_id, uint16_t a_ser, uint8_t a_cre) { - s.id = a_id & 0x7fff; s.serial = a_ser & 0x1fff; s.creation = a_cre & 0x03; - } - } u; - atom node; - - pid_blob(const atom& a_node, int a_id, int8_t a_cre) - : u(a_id, a_cre), node(a_node) + uint32_t id; // only 15 bits may be used and the rest must be 0 + uint32_t serial; // only 13 bits may be used and the rest must be 0 + uint32_t creation; + atom node; + + pid_blob(const atom& a_node, int a_id, int a_cre) + : id(a_id), serial(0), creation(a_cre), node(a_node) + {} + + pid_blob(const atom& a_node, int a_id, int serial, int a_cre) + : id(a_id), serial(serial), creation(a_cre), node(a_node) {} }; - BOOST_STATIC_ASSERT(sizeof(pid_blob) == sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(pid_blob) == sizeof(uint64_t)*2); blob* m_blob; @@ -89,10 +78,10 @@ class epid { } // Must only be called from constructor! - void init(const atom& node, int id, uint8_t creation, const Alloc& alloc) + void init(const atom& node, int id, int serial, int creation, const Alloc& alloc) { m_blob = new blob(1, alloc); - new (m_blob->data()) pid_blob(node, id, creation); + new (m_blob->data()) pid_blob(node, id, serial, creation); #ifdef EIXX_DEBUG std::cerr << "Initialized pid " << *this << " [addr=" << this << ", blob=" << m_blob << ']' << std::endl; @@ -125,14 +114,14 @@ class epid { : epid(atom(node), id, serial, creation, a_alloc) {} - epid(const atom& node, int id, int serial, int creation, const Alloc& a_alloc = Alloc()) - : epid(node, (id & 0x7fff) | ((serial & 0x1fff) << 15), creation, a_alloc) + epid(const atom& node, int id, int creation, const Alloc& a_alloc = Alloc()) + : epid(node, id, 0, creation, a_alloc) {} - epid(const atom& node, int id, int creation, const Alloc& a_alloc = Alloc()) + epid(const atom& node, int id, int serial, int creation, const Alloc& a_alloc = Alloc()) { detail::check_node_length(node.size()); - init(node, id, creation, a_alloc); + init(node, id, serial, creation, a_alloc); } /// Decode the pid from a binary buffer. @@ -183,24 +172,24 @@ class epid { * Get the id number from the PID. * @return the id number from the PID. **/ - int id() const { return m_blob ? m_blob->data()->u.s.id : 0; } + int id() const { return m_blob ? m_blob->data()->id : 0; } /** * Get the serial number from the PID. * @return the serial number from the PID. **/ - int serial() const { return m_blob ? m_blob->data()->u.s.serial : 0; } + int serial() const { return m_blob ? m_blob->data()->serial : 0; } /** * Get the creation number from the PID. * @return the creation number from the PID. **/ - int creation() const { return m_blob ? m_blob->data()->u.s.creation : 0; } + int creation() const { return m_blob ? m_blob->data()->creation : 0; } - uint32_t id_internal() const { return m_blob ? m_blob->data()->u.i & 0x3FFFffff : 0; } + uint32_t id_internal() const { return m_blob ? m_blob->data()->id : 0; } bool operator== (const epid& rhs) const { - return id_internal() == rhs.id_internal() && node() == rhs.node(); + return ::memcmp(m_blob->data(), rhs.m_blob->data(), sizeof(pid_blob)) == 0; } bool operator!= (const epid& rhs) const { return !(*this == rhs); } @@ -211,17 +200,22 @@ class epid { if (n > 0) return false; if (id_internal() < t2.id_internal()) return true; if (id_internal() > t2.id_internal()) return false; + if (serial() < t2.serial()) return true; + if (creation() > t2.creation()) return false; + if (creation() < t2.creation()) return true; return false; } - size_t encode_size() const { return 13 + node().size(); } + size_t encode_size() const { return 16 + node().size(); } void encode(char* buf, int& idx, size_t size) const; std::ostream& dump(std::ostream& out, const varbind* binding=NULL) const { - return out << "#Pid<" << node() - << '.' << id() << '.' << serial() << '.' << creation() << ">"; + out << "#Pid<" << node() + << '.' << id() << '.' << serial(); + if (creation() > 0) + out << ',' << creation(); + return out << '>'; } - }; } // namespace marshal diff --git a/include/eixx/marshal/pid.hxx b/include/eixx/marshal/pid.hxx index 52eded6..9d3ca23 100644 --- a/include/eixx/marshal/pid.hxx +++ b/include/eixx/marshal/pid.hxx @@ -37,8 +37,9 @@ void epid::decode(const char *buf, int& idx, size_t size, const Alloc& al { const char* s = buf + idx; const char* s0 = s; - if (get8(s) != ERL_PID_EXT) - throw err_decode_exception("Error decoding pid", -1); + auto n = get8(s); + if (n != ERL_PID_EXT && n != ERL_NEW_PID_EXT) + throw err_decode_exception("Error decoding pid", n); int len = atom::get_len(s); if (len < 0) @@ -48,12 +49,11 @@ void epid::decode(const char *buf, int& idx, size_t size, const Alloc& al atom l_node(s, len); s += len; - uint64_t i1 = get32be(s); - uint64_t i2 = get32be(s); - uint64_t l_id = i1 | i2 << 15; - int l_creation = get8(s); + uint32_t l_id = get32be(s); + uint32_t l_ser = get32be(s); + uint32_t l_cre = n == ERL_NEW_PID_EXT ? get32be(s) : (get8(s) & 0x03); - init(l_node, l_id, l_creation, alloc); + init(l_node, l_id, l_ser, l_cre, alloc); idx += s - s0; BOOST_ASSERT((size_t)idx <= size); @@ -64,7 +64,7 @@ void epid::encode(char* buf, int& idx, size_t size) const { char* s = buf + idx; char* s0 = s; - put8(s,ERL_PID_EXT); + put8(s,ERL_NEW_PID_EXT); put8(s,ERL_ATOM_UTF8_EXT); const std::string& nd = node().to_string(); unsigned short n = nd.size(); @@ -73,9 +73,9 @@ void epid::encode(char* buf, int& idx, size_t size) const s += n; /* now the integers */ - put32be(s, id() & 0x7fff); /* 15 bits */ - put32be(s, serial() & 0x1fff); /* 13 bits */ - put8(s, (creation() & 0x03)); /* 2 bits */ + put32be(s, id()); /* 15 bits */ + put32be(s, serial()); /* 13 bits */ + put32be(s, creation()); /* 2 bits */ idx += s-s0; BOOST_ASSERT((size_t)idx <= size); diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index dd98928..25bdf59 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -45,11 +45,11 @@ namespace marshal { template class port { struct port_blob { - uint8_t creation; - int id; - atom node; + uint32_t creation; + uint64_t id; + atom node; - port_blob(const atom& a_node, int a_id, uint8_t a_cre) + port_blob(const atom& a_node, uint64_t a_id, uint32_t a_cre) : creation(a_cre), id(a_id), node(a_node) {} }; @@ -62,11 +62,11 @@ class port { } // Must only be called from constructor! - void init(const atom& node, int id, uint8_t creation, + void init(const atom& node, uint64_t id, uint32_t creation, const Alloc& alloc) { m_blob = new blob(1, alloc); - new (m_blob->data()) port_blob(node, id & 0x0fffffff, creation & 0x03); + new (m_blob->data()) port_blob(node, id, creation); } public: @@ -139,13 +139,13 @@ class port { * Get the id number from the PORT. * @return the id number from the PORT. **/ - int id() const { return m_blob ? m_blob->data()->id : 0; } + uint64_t id() const { return m_blob ? m_blob->data()->id : 0; } /** * Get the creation number from the PORT. * @return the creation number from the PORT. **/ - int creation() const { return m_blob ? m_blob->data()->creation : 0; } + uint32_t creation() const { return m_blob ? m_blob->data()->creation : 0; } bool operator== (const port& t) const { return id() == t.id() && node() == t.node() && creation() == t.creation(); @@ -163,7 +163,7 @@ class port { return false; } - size_t encode_size() const { return 9 + node().size(); } + size_t encode_size() const { return (id() > 0x0fffffff ? 16 : 12) + node().size(); } void encode(char* buf, int& idx, size_t size) const; @@ -178,7 +178,10 @@ class port { namespace std { template ostream& operator<< (ostream& out, const eixx::marshal::port& a) { - return out << "#Port<" << a.node() << "." << a.id() << ">"; + out << "#Port<" << a.node() << "." << a.id(); + if (a.creation() > 0) + out << ',' << a.creation(); + return out << '>'; } } // namespace std diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index 8768770..3e77a28 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -35,21 +35,39 @@ namespace marshal { template port::port(const char *buf, int& idx, size_t size, const Alloc& a_alloc) { - const char* s = buf + idx; - const char* s0 = s; - if (get8(s) != ERL_PORT_EXT) - throw err_decode_exception("Error decoding port", -1); + const char* s = buf + idx; + const char* s0 = s; + auto tag = get8(s); + if (tag != ERL_PORT_EXT && + tag != ERL_NEW_PORT_EXT && + tag != ERL_V4_PORT_EXT) + throw err_decode_exception("Error decoding port", idx, tag); int len = atom::get_len(s); if (len < 0) - throw err_decode_exception("Error decoding port node", -1); + throw err_decode_exception("Error decoding port node", idx, len); detail::check_node_length(len); atom l_node(s, len); s += len; - int l_id = get32be(s) & 0x0fffffff; /* 28 bits */ - uint8_t l_cre = get8(s) & 0x03; /* 2 bits */ - init(l_node, l_id, l_cre, a_alloc); + uint64_t id; + uint32_t cre; + + switch (tag) { + case ERL_V4_PORT_EXT: + id = get64be(s); + cre = get32be(s); + break; + case ERL_NEW_PORT_EXT: + id = uint64_t(get32be(s)); + cre = get32be(s); + break; + case ERL_PORT_EXT: + id = uint64_t(get32be(s)) & 0x0fffffff; /* 28 bits */ + cre = get8(s) & 0x03; /* 2 bits */ + break; + } + init(l_node, id, cre, a_alloc); idx += s - s0; BOOST_ASSERT((size_t)idx <= size); @@ -60,7 +78,7 @@ void port::encode(char* buf, int& idx, size_t size) const { char* s = buf + idx; char* s0 = s; - put8(s,ERL_PORT_EXT); + s++; // Skip ERL_PORT_EXT put8(s,ERL_ATOM_UTF8_EXT); const std::string& str = node().to_string(); unsigned short n = str.size(); @@ -68,9 +86,15 @@ void port::encode(char* buf, int& idx, size_t size) const memmove(s, str.c_str(), n); s += n; - /* now the integers */ - put32be(s, id() & 0x0fffffff); /* 28 bits */ - put8(s, (creation() & 0x03)); /* 2 bits */ + if (id() > 0x0fffffff /* 28 bits */) { + *s0 = ERL_V4_PORT_EXT; + put64be(s, id()); + put32be(s, creation()); + } else { + *s0 = ERL_PORT_EXT; + put32be(s, id()); + put32be(s, creation()); + } idx += s-s0; BOOST_ASSERT((size_t)idx <= size); diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index b9c95d0..4cfd818 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -47,36 +47,48 @@ namespace detail { */ template class ref { - enum { COUNT = 3 }; + enum { COUNT = 5 }; struct ref_blob { - atom node; - union { - uint32_t ids[COUNT+1]; - struct { - uint32_t id0; - uint64_t id1; - uint32_t creation; - } __attribute__((__packed__)) s; - } u; - - ref_blob(const atom& a_node, uint32_t a_id0, uint64_t a_id1, uint8_t a_cre) + atom node; + uint32_t len; + uint32_t ids[COUNT]; + uint32_t creation; + + ref_blob(const atom& a_node, const uint32_t* a_ids, size_t n, uint32_t a_cre) : node(a_node) + , len(n) + , creation(a_cre) { - u.s.id0 = a_id0 & 0x3ffff; - u.s.id1 = a_id1; - u.s.creation = a_cre & 0x3; + assert(n >= 3 && n <= COUNT); + + int i = 0; + for (auto p = a_ids, e = a_ids+std::min(COUNT,n); p != e; ++p) + ids[i++] = *p; + + while(i < COUNT) + ids[i++] = 0; } + template + ref_blob(const atom& node, uint32_t (&ids)[N], uint32_t creation) + : ref_blob(node, ids, N, creation) + {} + + ref_blob(const atom& a_node, std::initializer_list a_ids, uint32_t a_cre) + : ref_blob(node, &*a_ids.begin(), a_ids.size(), creation) + {} }; blob* m_blob; // Must only be called from constructor! - void init(const atom& a_node, uint32_t a_id0, uint64_t a_id1, uint8_t a_cre, + void init(const atom& a_node, const uint32_t* a_ids, size_t n, uint32_t a_cre, const Alloc& alloc) { + detail::check_node_length(a_node.size()); + m_blob = new blob(1, alloc); - new (m_blob->data()) ref_blob(a_node, a_id0, a_id1, a_cre); + new (m_blob->data()) ref_blob(a_node, a_ids, n, a_cre); } void release() { @@ -84,12 +96,12 @@ class ref { m_blob->release(); } - uint32_t id0() const { return m_blob->data()->u.s.id0; } - uint64_t id1() const { return m_blob->data()->u.s.id1; } + uint32_t id0() const { return m_blob->data()->ids[0]; } + uint64_t id1() const { return m_blob->data()->ids[1]; } public: inline static const uint32_t* s_ref_ids() { - static const uint32_t s_ref_ids[] = {0, 0, 0}; + static const uint32_t s_ref_ids[] = {0, 0, 0, 0, 0}; return s_ref_ids; } @@ -108,32 +120,30 @@ class ref { * 2 bits will be used. * @throw err_bad_argument if node is empty or greater than MAX_NODE_LENGTH */ - template - ref(const char* node, uint32_t (&ids)[N], unsigned int creation, + ref(const atom& node, const uint32_t* a_ids, size_t n, unsigned int creation, const Alloc& a_alloc = Alloc()) - : ref(atom(node), ids[0], ids[1], ids[2], creation, a_alloc) - {} + { + init(node, a_ids, n, creation, a_alloc); + } template ref(const atom& node, uint32_t (&ids)[N], unsigned int creation, const Alloc& a_alloc = Alloc()) - : ref(node, ids[0], ids[1], ids[2], creation, a_alloc) + : ref(node, ids, N, creation, a_alloc) { - BOOST_STATIC_ASSERT(N == 3); + BOOST_STATIC_ASSERT(N >= 3 && N <= 5); } ref(const atom& node, uint32_t id0, uint32_t id1, uint32_t id2, unsigned int creation, const Alloc& a_alloc = Alloc()) - : ref(node, id0, id1 | ((uint64_t)id2 << 32), creation, a_alloc) + : ref(node, {id0, id1, id2}, creation, a_alloc) {} // For internal use - ref(const atom& node, uint32_t id0, uint64_t id1, uint8_t creation, + ref(const atom& node, std::initializer_list a_ids, uint8_t creation, const Alloc& a_alloc = Alloc()) - { - detail::check_node_length(node.size()); - init(node, id0, id1, creation, a_alloc); - } + : ref(node, &*a_ids.begin(), a_ids.size(), creation, a_alloc) + {} /** * Construct the object by decoding it from a binary @@ -177,7 +187,7 @@ class ref { * @return the id number from the REF. */ uint32_t id(uint32_t index) const { - BOOST_ASSERT(index < COUNT); + BOOST_ASSERT(index < len()); return ids()[index]; } @@ -185,17 +195,22 @@ class ref { * Get the id array from the REF. * @return the id array number from the REF. */ - const uint32_t* ids() const { return m_blob ? m_blob->data()->u.ids : s_ref_ids(); } + const uint32_t* ids() const { return m_blob ? m_blob->data()->ids : s_ref_ids(); } + + /** + * Get the id array from the REF. + * @return the id array number from the REF. + */ + const size_t len() const { return m_blob ? m_blob->data()->len : 0; } /** * Get the creation number from the REF. * @return the creation number from the REF. */ - int creation() const { return m_blob ? m_blob->data()->u.s.creation : 0; } + int creation() const { return m_blob ? m_blob->data()->creation : 0; } bool operator==(const ref& t) const { - return node() == t.node() && - ::memcmp(&m_blob->data()->u, &t.m_blob->data()->u, sizeof(m_blob->data()->u)) == 0; + return ::memcmp(m_blob->data(), t.m_blob->data(), sizeof(ref_blob)) == 0; } /// Less operator, needed for maps @@ -204,15 +219,22 @@ class ref { if (!m_blob) return true; int n = node().compare(rhs.node()); if (n != 0) return n < 0; - if (id0() > rhs.id0()) return true; - if (id0() > rhs.id0()) return false; - if (id1() < rhs.id1()) return true; - if (id1() > rhs.id1()) return false; + auto e = std::min(len(), rhs.len()); + for (size_t i=0; i < e; ++i) { + auto i1 = id(i); + auto i2 = rhs.id(i); + if (i1 > i2) return false; + if (i1 < i2) return true; + } + if (len() < rhs.len()) return true; + if (len() > rhs.len()) return false; + if (creation() < rhs.creation()) return true; + if (creation() > rhs.creation()) return false; return false; } size_t encode_size() const - { return 1+2+(3+node().size()) + COUNT*4 + 1; } + { return 1+2+(3+node().size()) + len()*4 + 4; } void encode(char* buf, int& idx, size_t size) const; @@ -231,8 +253,12 @@ namespace std { **/ template ostream& operator<< (ostream& out, const eixx::marshal::ref& a) { - return out << "#Ref<" << a.node() << '.' - << a.id(0) << '.' << a.id(1) << '.' << a.id(2) << '>'; + out << "#Ref<" << a.node(); + for (int i=0, e=a.len(); i != e; ++i) + out << '.' << a.id(i); + if (a.creation() > 0) + out << ',' << a.creation(); + return out << '>'; } } // namespace std diff --git a/include/eixx/marshal/ref.hxx b/include/eixx/marshal/ref.hxx index 7626c51..0d4339b 100644 --- a/include/eixx/marshal/ref.hxx +++ b/include/eixx/marshal/ref.hxx @@ -42,23 +42,43 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) int type = get8(s); switch (type) { - case ERL_NEW_REFERENCE_EXT: { - int count = get16be(s); - if (count != COUNT) - throw err_decode_exception("Error decoding ref's count", idx+1); + case ERL_NEW_REFERENCE_EXT: + case ERL_NEWER_REFERENCE_EXT: { + int count = get16be(s); // First goes the count + if (count < 0 || count > COUNT) + throw err_decode_exception("Error decoding ref's count", idx+1, count); int len = atom::get_len(s); if (len < 0) - throw err_decode_exception("Error decoding ref's atom", idx+3); + throw err_decode_exception("Error decoding ref's atom", idx+3, len); detail::check_node_length(len); - atom l_node(s, len); + atom nd(s, len); s += len; - uint8_t l_creation = get8(s) & 0x03; - uint32_t l_id0 = get32be(s); - uint64_t l_id1 = get32be(s) | ((uint64_t)get32be(s) << 32); + uint32_t cre = type == ERL_NEW_REFERENCE_EXT ? (get8(s) & 0x03) + : get32be(s); - init(l_node, l_id0, l_id1, l_creation, a_alloc); + uint32_t vals[COUNT]; + for (auto p=vals, e=p+count; p != e; ++p) + *p = uint32_t(get32be(s)); + + init(nd, vals, count, cre, a_alloc); + + idx += s-s0; + break; + } + case ERL_REFERENCE_EXT: { + int len = atom::get_len(s); + if (len < 0) + throw err_decode_exception("Error decoding ref's atom", idx+3, len); + detail::check_node_length(len); + atom nd(s, len); + s += len; + + uint32_t id = get32be(s); + uint32_t cre = get8(s) & 0x03; + + init(nd, &id, 1u, cre, a_alloc); idx += s-s0; break; @@ -73,9 +93,9 @@ void ref::encode(char* buf, int& idx, size_t size) const { char* s = buf + idx; char* s0 = s; - put8(s,ERL_NEW_REFERENCE_EXT); + put8(s,ERL_NEWER_REFERENCE_EXT); /* first, number of integers */ - put16be(s, COUNT); + put16be(s, len()); /* then the nodename */ put8(s,ERL_ATOM_UTF8_EXT); const std::string& str = node().to_string(); @@ -86,17 +106,10 @@ void ref::encode(char* buf, int& idx, size_t size) const /* now the integers */ if (m_blob) { - put8(s, m_blob->data()->u.s.creation); /* 2 bits */ - put32be(s, id0()); - put32be(s, id1() & 0xFFFF); - put32be(s, (id1() >> 32) & 0xFFFF); - } else { - put8(s, 0); /* 2 bits */ - put32be(s, 0u); - put32be(s, 0u); - put32be(s, 0u); + put32be(s, m_blob->data()->creation); + for (auto* p = ids(), *e = p + len(); p != e; ++p) + put32be(s, *p); } - idx += s-s0; BOOST_ASSERT((size_t)idx <= size); } diff --git a/src/basic_otp_node_local.cpp b/src/basic_otp_node_local.cpp index a6d896c..19c6043 100644 --- a/src/basic_otp_node_local.cpp +++ b/src/basic_otp_node_local.cpp @@ -62,14 +62,12 @@ std::string basic_otp_node_local::s_localhost = boost::asio::ip::host_name( basic_otp_node_local::basic_otp_node_local( const std::string& a_nodename, const std::string& a_cookie) - throw (std::runtime_error, err_bad_argument) { set_nodename(a_nodename, a_cookie); } void basic_otp_node_local::set_nodename( const std::string& a_nodename, const std::string& a_cookie) - throw (std::runtime_error, err_bad_argument) { if (m_cookie.size() > EI_MAX_COOKIE_SIZE) throw err_bad_argument("Cookie size too long", m_cookie.size()); diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index d43ced0..d5ecac1 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -31,27 +31,27 @@ BOOST_AUTO_TEST_CASE( test_type ) { { eterm t(10); - BOOST_REQUIRE_EQUAL(10, t.get()); - BOOST_REQUIRE_EQUAL(10, t.get()); - BOOST_REQUIRE_EQUAL(10, t.get()); - BOOST_REQUIRE_EQUAL(10, t.get()); - BOOST_REQUIRE_EQUAL(10, t.get()); - BOOST_REQUIRE_EQUAL(10, t.get()); + BOOST_CHECK_EQUAL(10, t.get()); + BOOST_CHECK_EQUAL(10, t.get()); + BOOST_CHECK_EQUAL(10, t.get()); + BOOST_CHECK_EQUAL(10, t.get()); + BOOST_CHECK_EQUAL(10, t.get()); + BOOST_CHECK_EQUAL(10, t.get()); BOOST_CHECK_THROW(t.get(), err_wrong_type); } { eterm t(10.0); - BOOST_REQUIRE_EQUAL(10.0, t.get()); + BOOST_CHECK_EQUAL(10.0, t.get()); BOOST_CHECK_THROW(t.get(), err_wrong_type); } { eterm t(true); - BOOST_REQUIRE_EQUAL(true, t.get()); + BOOST_CHECK_EQUAL(true, t.get()); BOOST_CHECK_THROW(t.get(), err_wrong_type); } { eterm t("ABC"); - BOOST_REQUIRE_EQUAL("ABC", t.get()); + BOOST_CHECK_EQUAL("ABC", t.get()); BOOST_CHECK_THROW(t.get(), err_wrong_type); } } @@ -59,31 +59,31 @@ BOOST_AUTO_TEST_CASE( test_type ) BOOST_AUTO_TEST_CASE( test_atomable ) { util::atom_table t(10); - BOOST_REQUIRE_EQUAL(0, t.lookup(std::string())); - BOOST_REQUIRE_EQUAL(0, t.lookup("")); + BOOST_CHECK_EQUAL(0, t.lookup(std::string())); + BOOST_CHECK_EQUAL(0, t.lookup("")); int n = t.lookup("abc"); - BOOST_REQUIRE(0 < n); - BOOST_REQUIRE(0 < t.lookup("aaaaa")); - BOOST_REQUIRE_EQUAL(n, t.lookup("abc")); + BOOST_CHECK(0 < n); + BOOST_CHECK(0 < t.lookup("aaaaa")); + BOOST_CHECK_EQUAL(n, t.lookup("abc")); } BOOST_AUTO_TEST_CASE( test_atom ) { { EIXX_DECL_ATOM(temp); - BOOST_REQUIRE_EQUAL("temp", am_temp); + BOOST_CHECK_EQUAL("temp", am_temp); EIXX_DECL_ATOM_VAR(am_temp2, "temp2"); - BOOST_REQUIRE_EQUAL("temp2", am_temp2); + BOOST_CHECK_EQUAL("temp2", am_temp2); } { auto n = util::atom_table().try_lookup("temp3"); - BOOST_REQUIRE_EQUAL(-1, n); + BOOST_CHECK_EQUAL(-1, n); auto s = std::string(MAXATOMLEN+1, 'X'); n = util::atom_table().try_lookup(s); - BOOST_REQUIRE_EQUAL(-2, n); + BOOST_CHECK_EQUAL(-2, n); n = util::atom_table().try_lookup(""); - BOOST_REQUIRE_EQUAL(0, n); + BOOST_CHECK_EQUAL(0, n); BOOST_CHECK_THROW(atom("temp3", true), err_atom_not_found); auto a = atom("temp3", false); @@ -91,33 +91,33 @@ BOOST_AUTO_TEST_CASE( test_atom ) } { atom a(""); - BOOST_REQUIRE_EQUAL(0, a.index()); - BOOST_REQUIRE_EQUAL(atom(), a); + BOOST_CHECK_EQUAL(0, a.index()); + BOOST_CHECK_EQUAL(atom(), a); } { atom et1("Abc"); - BOOST_REQUIRE(et1.index() > 0); + BOOST_CHECK(et1.index() > 0); atom et2("aBc"); - BOOST_REQUIRE_NE(et1, et2); + BOOST_CHECK_NE(et1, et2); atom et3("Abc"); - BOOST_REQUIRE_EQUAL(et1, et3); - BOOST_REQUIRE_EQUAL(et1.index(), et3.index()); + BOOST_CHECK_EQUAL(et1, et3); + BOOST_CHECK_EQUAL(et1.index(), et3.index()); } { const uint8_t buf[] = {ERL_ATOM_UTF8_EXT,0,3,97,98,99}; int i = 0; atom atom((const char*)buf, i, sizeof(buf)); - BOOST_REQUIRE_EQUAL(6, i); - BOOST_REQUIRE_EQUAL("abc", atom); - BOOST_REQUIRE_EQUAL(std::string("abc"), atom.c_str()); - BOOST_REQUIRE_EQUAL(atom.c_str(), std::string("abc")); + BOOST_CHECK_EQUAL(6, i); + BOOST_CHECK_EQUAL("abc", atom); + BOOST_CHECK_EQUAL(std::string("abc"), atom.c_str()); + BOOST_CHECK_EQUAL(atom.c_str(), std::string("abc")); eterm et1(atom); - BOOST_REQUIRE_EQUAL(std::string("abc"), et1.to_string()); + BOOST_CHECK_EQUAL(std::string("abc"), et1.to_string()); eterm et2(marshal::atom("Abc")); - BOOST_REQUIRE_EQUAL("'Abc'", et2.to_string()); + BOOST_CHECK_EQUAL("'Abc'", et2.to_string()); - BOOST_REQUIRE_EQUAL("a", et1.to_string(1)); + BOOST_CHECK_EQUAL("a", et1.to_string(1)); } } @@ -127,23 +127,23 @@ BOOST_AUTO_TEST_CASE( test_bool ) { int n; eterm et(true); - BOOST_REQUIRE(et.initialized()); - BOOST_REQUIRE_EQUAL(BOOL, et.type()); + BOOST_CHECK(et.initialized()); + BOOST_CHECK_EQUAL(BOOL, et.type()); // Since the encode_size() functions for bool and double don't call // ei's implementation but have hard-coded values inlined for efficiency, // test that our assumption of the return matches the return of the // corresponding ei's implementation: - BOOST_REQUIRE_EQUAL(6, marshal::visit_eterm_encode_size_calc()(true)); - BOOST_REQUIRE_EQUAL(7, marshal::visit_eterm_encode_size_calc()(false)); - BOOST_REQUIRE_EQUAL(9, marshal::visit_eterm_encode_size_calc()(0.0)); + BOOST_CHECK_EQUAL(6, marshal::visit_eterm_encode_size_calc()(true)); + BOOST_CHECK_EQUAL(7, marshal::visit_eterm_encode_size_calc()(false)); + BOOST_CHECK_EQUAL(9, marshal::visit_eterm_encode_size_calc()(0.0)); n = 0; - BOOST_REQUIRE_EQUAL(0, ei_encode_boolean(NULL, &n, true)); + BOOST_CHECK_EQUAL(0, ei_encode_boolean(NULL, &n, true)); BOOST_CHECK_EQUAL(n, marshal::visit_eterm_encode_size_calc()(true)); n = 0; - BOOST_REQUIRE_EQUAL(0, ei_encode_boolean(NULL, &n, false)); + BOOST_CHECK_EQUAL(0, ei_encode_boolean(NULL, &n, false)); BOOST_CHECK_EQUAL(n, marshal::visit_eterm_encode_size_calc()(false)); n = 0; - BOOST_REQUIRE_EQUAL(0, ei_encode_double(NULL, &n, 0.0)); + BOOST_CHECK_EQUAL(0, ei_encode_double(NULL, &n, 0.0)); BOOST_CHECK_EQUAL(n, marshal::visit_eterm_encode_size_calc()(0.0)); } @@ -151,16 +151,16 @@ BOOST_AUTO_TEST_CASE( test_bool ) const uint8_t buf[] = {ERL_ATOM_UTF8_EXT,0,4,116,114,117,101}; int i = 0; eterm t((const char*)buf, i, sizeof(buf), alloc); - BOOST_REQUIRE_EQUAL(true, t.to_bool()); - BOOST_REQUIRE_EQUAL(std::string("true"), t.to_string()); + BOOST_CHECK_EQUAL(true, t.to_bool()); + BOOST_CHECK_EQUAL(std::string("true"), t.to_string()); } { const uint8_t buf[] = {ERL_ATOM_UTF8_EXT,0,5,102,97,108,115,101}; int i = 0; eterm t((const char*)buf, i, sizeof(buf), alloc); - BOOST_REQUIRE_EQUAL(sizeof(buf), (size_t)i); - BOOST_REQUIRE_EQUAL(false, t.to_bool()); - BOOST_REQUIRE_EQUAL(std::string("false"), t.to_string()); + BOOST_CHECK_EQUAL(sizeof(buf), (size_t)i); + BOOST_CHECK_EQUAL(false, t.to_bool()); + BOOST_CHECK_EQUAL(std::string("false"), t.to_string()); } } @@ -172,9 +172,9 @@ BOOST_AUTO_TEST_CASE( test_binary ) { binary et("Abc", 3, alloc); } { binary et{1,2,109}; - BOOST_REQUIRE_EQUAL(3u, et.size()); - BOOST_REQUIRE_EQUAL("<<1,2,109>>", eterm(et).to_string()); - BOOST_REQUIRE_EQUAL("<<>>", eterm(binary({}, alloc)).to_string()); + BOOST_CHECK_EQUAL(3u, et.size()); + BOOST_CHECK_EQUAL("<<1,2,109>>", eterm(et).to_string()); + BOOST_CHECK_EQUAL("<<>>", eterm(binary({}, alloc)).to_string()); } { @@ -183,9 +183,9 @@ BOOST_AUTO_TEST_CASE( test_binary ) binary term1((const char*)buf, i, sizeof(buf), alloc); i = 0; binary term2((const char*)buf, i, sizeof(buf), alloc); - BOOST_REQUIRE_EQUAL(term1, term2); + BOOST_CHECK_EQUAL(term1, term2); eterm et(term1); - BOOST_REQUIRE_EQUAL("<<\"abc\">>", et.to_string()); + BOOST_CHECK_EQUAL("<<\"abc\">>", et.to_string()); } } @@ -201,13 +201,13 @@ BOOST_AUTO_TEST_CASE( test_list ) eterm(atom("efg")) }; eterm et = list(l); - BOOST_REQUIRE(et.initialized()); + BOOST_CHECK(et.initialized()); } { list l{1, 2, 3, "abc", 2.0, atom("efg")}; eterm et = l; - BOOST_REQUIRE_EQUAL(6, l.length()); - BOOST_REQUIRE(et.initialized()); + BOOST_CHECK_EQUAL(6, l.length()); + BOOST_CHECK(et.initialized()); } { eterm items[] = { @@ -217,22 +217,22 @@ BOOST_AUTO_TEST_CASE( test_list ) list l(2, alloc); l.push_back(items[0]); l.push_back(items[1]); - BOOST_REQUIRE(!l.initialized()); + BOOST_CHECK(!l.initialized()); l.close(); - BOOST_REQUIRE(l.initialized()); - BOOST_REQUIRE_EQUAL(2u, l.length()); + BOOST_CHECK(l.initialized()); + BOOST_CHECK_EQUAL(2u, l.length()); eterm et(l); - BOOST_REQUIRE_EQUAL(2u, et.to_list().length()); + BOOST_CHECK_EQUAL(2u, et.to_list().length()); } { eterm items[] = { eterm(atom("abc")), eterm(atom("efg")) }; list l(items, alloc); - BOOST_REQUIRE(l.initialized()); - BOOST_REQUIRE_EQUAL(2u, l.length()); + BOOST_CHECK(l.initialized()); + BOOST_CHECK_EQUAL(2u, l.length()); list::iterator it = l.begin(); - BOOST_REQUIRE_EQUAL("efg", (++it)->to_string()); + BOOST_CHECK_EQUAL("efg", (++it)->to_string()); eterm et(l); - BOOST_REQUIRE_EQUAL("[abc,efg]", et.to_string()); + BOOST_CHECK_EQUAL("[abc,efg]", et.to_string()); } { eterm items[] = { @@ -241,16 +241,16 @@ BOOST_AUTO_TEST_CASE( test_list ) eterm(3) }; list et(items, alloc); - BOOST_REQUIRE_EQUAL(3u, et.length()); + BOOST_CHECK_EQUAL(3u, et.length()); const list& cp1 = et.tail(0); - BOOST_REQUIRE_EQUAL(2u, cp1.length()); + BOOST_CHECK_EQUAL(2u, cp1.length()); list::const_iterator it = cp1.begin(); - BOOST_REQUIRE_EQUAL(LONG, it->type()); - BOOST_REQUIRE_EQUAL(2, (it++)->to_long()); - BOOST_REQUIRE_EQUAL(LONG, it->type()); - BOOST_REQUIRE_EQUAL(3, (it++)->to_long()); - BOOST_REQUIRE(cp1.end() == it); + BOOST_CHECK_EQUAL(LONG, it->type()); + BOOST_CHECK_EQUAL(2, (it++)->to_long()); + BOOST_CHECK_EQUAL(LONG, it->type()); + BOOST_CHECK_EQUAL(3, (it++)->to_long()); + BOOST_CHECK(cp1.end() == it); } } @@ -259,48 +259,48 @@ BOOST_AUTO_TEST_CASE( test_list3 ) allocator_t alloc; { list t = list::make(1, alloc); - BOOST_REQUIRE_EQUAL(1ul, t.length()); - BOOST_REQUIRE_EQUAL(1l, t.nth(0).to_long()); + BOOST_CHECK_EQUAL(1ul, t.length()); + BOOST_CHECK_EQUAL(1l, t.nth(0).to_long()); } { const list& t = list::make(1, 2, alloc); - BOOST_REQUIRE_EQUAL(2ul, t.length()); - BOOST_REQUIRE_EQUAL(1, t.nth(0).to_long()); - BOOST_REQUIRE_EQUAL(2, t.nth(1).to_long()); + BOOST_CHECK_EQUAL(2ul, t.length()); + BOOST_CHECK_EQUAL(1, t.nth(0).to_long()); + BOOST_CHECK_EQUAL(2, t.nth(1).to_long()); } { const list& t = list::make(1,2,3, alloc); - BOOST_REQUIRE_EQUAL(3ul, t.length()); - BOOST_REQUIRE_EQUAL(1, t.nth(0).to_long()); - BOOST_REQUIRE_EQUAL(2, t.nth(1).to_long()); - BOOST_REQUIRE_EQUAL(3, t.nth(2).to_long()); + BOOST_CHECK_EQUAL(3ul, t.length()); + BOOST_CHECK_EQUAL(1, t.nth(0).to_long()); + BOOST_CHECK_EQUAL(2, t.nth(1).to_long()); + BOOST_CHECK_EQUAL(3, t.nth(2).to_long()); } { const list& t = list::make(1,2,3,4, alloc); - BOOST_REQUIRE_EQUAL(4ul, t.length()); - BOOST_REQUIRE_EQUAL(1, t.nth(0).to_long()); - BOOST_REQUIRE_EQUAL(2, t.nth(1).to_long()); - BOOST_REQUIRE_EQUAL(3, t.nth(2).to_long()); - BOOST_REQUIRE_EQUAL(4, t.nth(3).to_long()); + BOOST_CHECK_EQUAL(4ul, t.length()); + BOOST_CHECK_EQUAL(1, t.nth(0).to_long()); + BOOST_CHECK_EQUAL(2, t.nth(1).to_long()); + BOOST_CHECK_EQUAL(3, t.nth(2).to_long()); + BOOST_CHECK_EQUAL(4, t.nth(3).to_long()); } { const list& t = list::make(1,2,3,4,5, alloc); - BOOST_REQUIRE_EQUAL(5ul, t.length()); - BOOST_REQUIRE_EQUAL(1, t.nth(0).to_long()); - BOOST_REQUIRE_EQUAL(2, t.nth(1).to_long()); - BOOST_REQUIRE_EQUAL(3, t.nth(2).to_long()); - BOOST_REQUIRE_EQUAL(4, t.nth(3).to_long()); - BOOST_REQUIRE_EQUAL(5, t.nth(4).to_long()); + BOOST_CHECK_EQUAL(5ul, t.length()); + BOOST_CHECK_EQUAL(1, t.nth(0).to_long()); + BOOST_CHECK_EQUAL(2, t.nth(1).to_long()); + BOOST_CHECK_EQUAL(3, t.nth(2).to_long()); + BOOST_CHECK_EQUAL(4, t.nth(3).to_long()); + BOOST_CHECK_EQUAL(5, t.nth(4).to_long()); } { const list& t = list::make(1,2,3,4,5,6, alloc); - BOOST_REQUIRE_EQUAL(6ul, t.length()); - BOOST_REQUIRE_EQUAL(1, t.nth(0).to_long()); - BOOST_REQUIRE_EQUAL(2, t.nth(1).to_long()); - BOOST_REQUIRE_EQUAL(3, t.nth(2).to_long()); - BOOST_REQUIRE_EQUAL(4, t.nth(3).to_long()); - BOOST_REQUIRE_EQUAL(5, t.nth(4).to_long()); - BOOST_REQUIRE_EQUAL(6, t.nth(5).to_long()); + BOOST_CHECK_EQUAL(6ul, t.length()); + BOOST_CHECK_EQUAL(1, t.nth(0).to_long()); + BOOST_CHECK_EQUAL(2, t.nth(1).to_long()); + BOOST_CHECK_EQUAL(3, t.nth(2).to_long()); + BOOST_CHECK_EQUAL(4, t.nth(3).to_long()); + BOOST_CHECK_EQUAL(5, t.nth(4).to_long()); + BOOST_CHECK_EQUAL(6, t.nth(5).to_long()); } } @@ -310,7 +310,7 @@ BOOST_AUTO_TEST_CASE( test_list4 ) for (int i=0; i<2; ++i) l.push_back(eterm(atom("abc"))); l.close(); - BOOST_REQUIRE_EQUAL(2u, l.length()); + BOOST_CHECK_EQUAL(2u, l.length()); { list l1{tuple{am_ok, 10}, tuple{am_error, "abc"}}; @@ -319,13 +319,13 @@ BOOST_AUTO_TEST_CASE( test_list4 ) eterm val; for (auto& item : l1) { - BOOST_REQUIRE(item.to_pair(opt, val)); + BOOST_CHECK(item.to_pair(opt, val)); if (opt == am_ok) - BOOST_REQUIRE_EQUAL(10, val.to_long()); + BOOST_CHECK_EQUAL(10, val.to_long()); else if (opt == am_error) - BOOST_REQUIRE_EQUAL("abc", val.to_str()); + BOOST_CHECK_EQUAL("abc", val.to_str()); else - BOOST_REQUIRE(false); + BOOST_CHECK(false); } } @@ -336,8 +336,8 @@ BOOST_AUTO_TEST_CASE( test_double ) allocator_t alloc; { eterm et1(10.0); - BOOST_REQUIRE_EQUAL(DOUBLE, et1.type()); - BOOST_REQUIRE(et1.initialized()); + BOOST_CHECK_EQUAL(DOUBLE, et1.type()); + BOOST_CHECK(et1.initialized()); } { @@ -346,28 +346,28 @@ BOOST_AUTO_TEST_CASE( test_double ) 43,48,48,0,0,0,0,0}; int i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); - BOOST_REQUIRE_EQUAL(32, i); - BOOST_REQUIRE_EQUAL(1.0, term.to_double()); + BOOST_CHECK_EQUAL(32, i); + BOOST_CHECK_EQUAL(1.0, term.to_double()); } { const uint8_t buf[] = {NEW_FLOAT_EXT,63,240,0,0,0,0,0,0}; int i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); - BOOST_REQUIRE_EQUAL(9, i); - BOOST_REQUIRE_EQUAL(1.0, term.to_double()); - BOOST_REQUIRE_EQUAL("1.0", term.to_string()); + BOOST_CHECK_EQUAL(9, i); + BOOST_CHECK_EQUAL(1.0, term.to_double()); + BOOST_CHECK_EQUAL("1.0", term.to_string()); } { eterm term(90.0); - BOOST_REQUIRE_EQUAL("90.0", term.to_string()); + BOOST_CHECK_EQUAL("90.0", term.to_string()); } { eterm term(900.0); - BOOST_REQUIRE_EQUAL("900.0", term.to_string()); + BOOST_CHECK_EQUAL("900.0", term.to_string()); } { eterm term(90.010000); - BOOST_REQUIRE_EQUAL("90.01", term.to_string()); + BOOST_CHECK_EQUAL("90.01", term.to_string()); } } @@ -376,28 +376,28 @@ BOOST_AUTO_TEST_CASE( test_long ) allocator_t alloc; { eterm et(100l * 1024 * 1024 * 1024); - BOOST_REQUIRE_EQUAL(LONG, et.type()); - BOOST_REQUIRE_EQUAL(100l * 1024 * 1024 * 1024, et.to_long()); + BOOST_CHECK_EQUAL(LONG, et.type()); + BOOST_CHECK_EQUAL(100l * 1024 * 1024 * 1024, et.to_long()); } { eterm et(1); - BOOST_REQUIRE(et.initialized()); + BOOST_CHECK(et.initialized()); } { const uint8_t buf[] = {ERL_INTEGER_EXT,7,91,205,21}; int i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); - BOOST_REQUIRE_EQUAL(5, i); - BOOST_REQUIRE_EQUAL (123456789, term.to_long()); - BOOST_REQUIRE_EQUAL("123456789", term.to_string()); + BOOST_CHECK_EQUAL(5, i); + BOOST_CHECK_EQUAL (123456789, term.to_long()); + BOOST_CHECK_EQUAL("123456789", term.to_string()); } { const uint8_t buf[] = {ERL_SMALL_BIG_EXT,4,1,210,2,150,73}; int i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); - BOOST_REQUIRE_EQUAL(7, i); - BOOST_REQUIRE_EQUAL (-1234567890, term.to_long()); - BOOST_REQUIRE_EQUAL("-1234567890", term.to_string()); + BOOST_CHECK_EQUAL(7, i); + BOOST_CHECK_EQUAL (-1234567890, term.to_long()); + BOOST_CHECK_EQUAL("-1234567890", term.to_string()); } } @@ -406,27 +406,27 @@ BOOST_AUTO_TEST_CASE( test_string ) allocator_t alloc; { eterm et("Abc", alloc); - BOOST_REQUIRE(et.initialized()); - BOOST_REQUIRE_EQUAL(STRING, et.type()); + BOOST_CHECK(et.initialized()); + BOOST_CHECK_EQUAL(STRING, et.type()); } { string s("a", alloc); std::string test("abcd"); s = test; - BOOST_REQUIRE_EQUAL(s, "abcd"); + BOOST_CHECK_EQUAL(s, "abcd"); } { const uint8_t buf[] = {ERL_STRING_EXT,0,3,97,98,99}; int i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); - BOOST_REQUIRE_EQUAL(6, i); - BOOST_REQUIRE_EQUAL("abc", term.to_str()); - BOOST_REQUIRE_EQUAL(term.to_str(), "abc"); - BOOST_REQUIRE_EQUAL(std::string("abc"), term.to_str()); - BOOST_REQUIRE_EQUAL(term.to_str(), std::string("abc")); - BOOST_REQUIRE_EQUAL(std::string("\"abc\""), term.to_string()); + BOOST_CHECK_EQUAL(6, i); + BOOST_CHECK_EQUAL("abc", term.to_str()); + BOOST_CHECK_EQUAL(term.to_str(), "abc"); + BOOST_CHECK_EQUAL(std::string("abc"), term.to_str()); + BOOST_CHECK_EQUAL(term.to_str(), std::string("abc")); + BOOST_CHECK_EQUAL(std::string("\"abc\""), term.to_string()); } } @@ -435,32 +435,34 @@ BOOST_AUTO_TEST_CASE( test_pid ) allocator_t alloc; { epid et("abc@fc12", 1, 2, 3, alloc); - BOOST_REQUIRE_EQUAL(atom("abc@fc12"), et.node()); - BOOST_REQUIRE_EQUAL(1, et.id()); - BOOST_REQUIRE_EQUAL(2, et.serial()); - BOOST_REQUIRE_EQUAL(3, et.creation()); + BOOST_CHECK_EQUAL(atom("abc@fc12"), et.node()); + BOOST_CHECK_EQUAL(1, et.id()); + BOOST_CHECK_EQUAL(2, et.serial()); + BOOST_CHECK_EQUAL(3, et.creation()); et = epid("abc@fc12", 1, 2, 4, alloc); - BOOST_REQUIRE_EQUAL(0, et.creation()); + BOOST_CHECK_EQUAL(4, et.creation()); eterm t(et); - BOOST_REQUIRE(t.initialized()); - BOOST_REQUIRE_EQUAL(PID, t.type()); - BOOST_REQUIRE_EQUAL("#Pid", t.to_string()); + BOOST_CHECK(t.initialized()); + BOOST_CHECK_EQUAL(PID, t.type()); + BOOST_CHECK_EQUAL("#Pid", t.to_string()); + + BOOST_CHECK_EQUAL("#Pid", eterm(epid("abc@fc12", 1, 2, 0, alloc)).to_string()); } { epid p1("a@fc12", 1, 2, 3, alloc); epid p2("a@fc12", 1, 2, 3, alloc); - BOOST_REQUIRE_EQUAL(p1, p2); + BOOST_CHECK_EQUAL(p1, p2); epid p3("a@fc", 1, 2, 3, alloc); - BOOST_REQUIRE_NE(p1, p3); + BOOST_CHECK_NE(p1, p3); epid p4("a@fc12", 4, 2, 3, alloc); - BOOST_REQUIRE_NE(p1, p4); + BOOST_CHECK_NE(p1, p4); epid p5("a@fc12", 1, 4, 3, alloc); - BOOST_REQUIRE_NE(p1, p5); + BOOST_CHECK_NE(p1, p5); epid p6("a@fc12", 1, 2, 4, alloc); - BOOST_REQUIRE_NE(p1, p6); + BOOST_CHECK_NE(p1, p6); } } @@ -469,29 +471,29 @@ BOOST_AUTO_TEST_CASE( test_map ) allocator_t alloc; { map m00, m01; - BOOST_REQUIRE_EQUAL(m00, m01); + BOOST_CHECK_EQUAL(m00, m01); map m{{1, 2.00}, {"abc", 10}}; - BOOST_REQUIRE_EQUAL(2ul, m.size()); - BOOST_REQUIRE_EQUAL(2.00, m[1].to_double()); - BOOST_REQUIRE_EQUAL(10, m["abc"].to_long()); + BOOST_CHECK_EQUAL(2ul, m.size()); + BOOST_CHECK_EQUAL(2.00, m[1].to_double()); + BOOST_CHECK_EQUAL(10, m["abc"].to_long()); map m1{{1, 2.00}, {"abc", 10}}; - BOOST_REQUIRE_EQUAL(m, m1); + BOOST_CHECK_EQUAL(m, m1); map m2{{1, 3.00}, {"abc", 10}}; - BOOST_REQUIRE_LT(m, m2); + BOOST_CHECK_LT(m, m2); } { // #{1=>2, a => 3} const uint8_t buf[] = {ERL_MAP_EXT,0,0,0,2,97,1,97,2,100,0,1,97,97,3}; int i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); - BOOST_REQUIRE_EQUAL(15, i); - BOOST_REQUIRE(term.is_map()); - BOOST_REQUIRE_EQUAL(2, term.to_map().size()); - BOOST_REQUIRE_EQUAL(2, term.to_map()[1].to_long()); - BOOST_REQUIRE_EQUAL(3, term.to_map()[atom("a")].to_long()); + BOOST_CHECK_EQUAL(15, i); + BOOST_CHECK(term.is_map()); + BOOST_CHECK_EQUAL(2, term.to_map().size()); + BOOST_CHECK_EQUAL(2, term.to_map()[1].to_long()); + BOOST_CHECK_EQUAL(3, term.to_map()[atom("a")].to_long()); } } @@ -520,7 +522,7 @@ BOOST_AUTO_TEST_CASE( test_less_then ) ss.insert(et1); ss.insert(et2); ss.insert(et1); - BOOST_REQUIRE_EQUAL(2ul, ss.size()); + BOOST_CHECK_EQUAL(2ul, ss.size()); } } @@ -529,25 +531,30 @@ BOOST_AUTO_TEST_CASE( test_port ) allocator_t alloc; { port et("abc@fc12", 1, 2, alloc); - BOOST_REQUIRE_EQUAL(atom("abc@fc12"), et.node()); - BOOST_REQUIRE_EQUAL(1, et.id()); - BOOST_REQUIRE_EQUAL(2, et.creation()); + BOOST_CHECK_EQUAL(atom("abc@fc12"), et.node()); + BOOST_CHECK_EQUAL(1, et.id()); + BOOST_CHECK_EQUAL(2, et.creation()); eterm t(et); - BOOST_REQUIRE(t.initialized()); - BOOST_REQUIRE_EQUAL(PORT, t.type()); - BOOST_REQUIRE_EQUAL("#Port", t.to_string()); + BOOST_CHECK(t.initialized()); + BOOST_CHECK_EQUAL(PORT, t.type()); + BOOST_CHECK_EQUAL("#Port", t.to_string()); + BOOST_CHECK_EQUAL("#Port", eterm(port("abc@fc12",1,0)).to_string()); + port et1("abc@fc12", 1, 2, alloc); + port et2("abc@fc12", 1, 0, alloc); + BOOST_CHECK_EQUAL(et1, et); + BOOST_CHECK_NE(et1, et2); } { port p1("a@fc12", 1, 2, alloc); port p2("a@fc12", 1, 2); - BOOST_REQUIRE_EQUAL(p1, p2); + BOOST_CHECK_EQUAL(p1, p2); port p3("a@fc", 1, 2, alloc); - BOOST_REQUIRE_NE(p1, p3); + BOOST_CHECK_NE(p1, p3); port p4("a@fc12", 4, 2, alloc); - BOOST_REQUIRE_NE(p1, p4); + BOOST_CHECK_NE(p1, p4); port p5("a@fc12", 1, 4, alloc); - BOOST_REQUIRE_NE(p1, p5); + BOOST_CHECK_NE(p1, p5); } } @@ -557,42 +564,49 @@ BOOST_AUTO_TEST_CASE( test_ref ) { uint32_t ids[] = {5,6,7}; ref et("abc@fc12", ids, 3, alloc); - BOOST_REQUIRE_EQUAL(atom("abc@fc12"), et.node()); - BOOST_REQUIRE_EQUAL(5u, et.id(0)); - BOOST_REQUIRE_EQUAL(6u, et.id(1)); - BOOST_REQUIRE_EQUAL(7u, et.id(2)); - BOOST_REQUIRE_EQUAL(3, et.creation()); + BOOST_CHECK_EQUAL(atom("abc@fc12"), et.node()); + BOOST_CHECK_EQUAL(5u, et.id(0)); + BOOST_CHECK_EQUAL(6u, et.id(1)); + BOOST_CHECK_EQUAL(7u, et.id(2)); + BOOST_CHECK_EQUAL(3, et.creation()); + + ref et2("abc@fc12", ids, 3, alloc); + BOOST_CHECK_EQUAL(et, et2); et = ref("abc@fc12", ids, 4, alloc); - BOOST_REQUIRE_EQUAL(0, et.creation()); + BOOST_CHECK_EQUAL(4, et.creation()); eterm t(et); - BOOST_REQUIRE(t.initialized()); - BOOST_REQUIRE_EQUAL(REF, t.type()); - BOOST_REQUIRE_EQUAL("#Ref", t.to_string()); + BOOST_CHECK(t.initialized()); + BOOST_CHECK_EQUAL(REF, t.type()); + BOOST_CHECK_EQUAL("#Ref", t.to_string()); + ref et1("abc@fc12", ids, 0, alloc); + BOOST_CHECK_EQUAL("#Ref", eterm(et1).to_string()); + BOOST_CHECK_NE(et, et1); + BOOST_CHECK_NE(et1, et2); } { uint32_t ids[] = {1,2,3}; ref p1("abc@fc12", ids, 4, alloc); ref p2("abc@fc12", ids, 4); - BOOST_REQUIRE_EQUAL(p1, p2); + BOOST_CHECK_EQUAL(p1, p2); ids[0] = 4; ref p3("abc@fc12", ids, 4); - BOOST_REQUIRE_NE(p1, p3); + BOOST_CHECK_NE(p1, p3); ids[0] = 1; ids[1] = 4; ref p4("abc@fc12", ids, 4); - BOOST_REQUIRE_NE(p1, p4); + BOOST_CHECK_NE(p1, p4); ids[1] = 2; ids[2] = 4; ref p5("abc@fc12", ids, 4); - BOOST_REQUIRE_NE(p1, p5); + BOOST_CHECK_NE(p1, p5); ids[2] = 3; ref p6("abc@fc12", ids, 4); - BOOST_REQUIRE_EQUAL(p1, p6); + BOOST_CHECK_EQUAL(p1, p6); ref p7("abc@fc12", ids, 5); - BOOST_REQUIRE_NE(p1, p7); + BOOST_CHECK_NE(p1, p7); } } @@ -601,7 +615,7 @@ BOOST_AUTO_TEST_CASE( test_tuple ) allocator_t alloc; { tuple et2(10, alloc); - BOOST_REQUIRE(!et2.initialized()); + BOOST_CHECK(!et2.initialized()); } { eterm l[] = { @@ -609,13 +623,13 @@ BOOST_AUTO_TEST_CASE( test_tuple ) eterm(atom("efg")) }; eterm et = tuple(l); - BOOST_REQUIRE(et.initialized()); + BOOST_CHECK(et.initialized()); } { tuple t{1, 2, 3, "abc", 2.0, atom("efg")}; eterm et = t; - BOOST_REQUIRE(et.initialized()); + BOOST_CHECK(et.initialized()); } eterm l[] = { @@ -632,9 +646,9 @@ BOOST_AUTO_TEST_CASE( test_tuple ) // Note that now the tuple owns previously dangling eterm pointers // in the list[] array. - BOOST_REQUIRE(et.initialized()); - BOOST_REQUIRE_EQUAL(4u, et.size()); - BOOST_REQUIRE_EQUAL("efg", et[1].to_string()); + BOOST_CHECK(et.initialized()); + BOOST_CHECK_EQUAL(4u, et.size()); + BOOST_CHECK_EQUAL("efg", et[1].to_string()); } BOOST_AUTO_TEST_CASE( test_tuple2 ) @@ -645,11 +659,11 @@ BOOST_AUTO_TEST_CASE( test_tuple2 ) tuple et(2, alloc); et.push_back(items[0]); et.push_back(items[1]); - BOOST_REQUIRE(et.initialized()); - BOOST_REQUIRE_EQUAL(2u, et.size()); - BOOST_REQUIRE_EQUAL("efg", et[1].to_string()); + BOOST_CHECK(et.initialized()); + BOOST_CHECK_EQUAL(2u, et.size()); + BOOST_CHECK_EQUAL("efg", et[1].to_string()); eterm term(et); - BOOST_REQUIRE_EQUAL("{'Abc',efg}", term.to_string()); + BOOST_CHECK_EQUAL("{'Abc',efg}", term.to_string()); } } @@ -658,48 +672,48 @@ BOOST_AUTO_TEST_CASE( test_tuple3 ) allocator_t alloc; { tuple t = tuple::make(1, alloc); - BOOST_REQUIRE_EQUAL(1ul, t.size()); - BOOST_REQUIRE_EQUAL(1, t[0].to_long()); + BOOST_CHECK_EQUAL(1ul, t.size()); + BOOST_CHECK_EQUAL(1, t[0].to_long()); } { const tuple& t = tuple::make(1, 2, alloc); - BOOST_REQUIRE_EQUAL(2ul, t.size()); - BOOST_REQUIRE_EQUAL(1, t[0].to_long()); - BOOST_REQUIRE_EQUAL(2, t[1].to_long()); + BOOST_CHECK_EQUAL(2ul, t.size()); + BOOST_CHECK_EQUAL(1, t[0].to_long()); + BOOST_CHECK_EQUAL(2, t[1].to_long()); } { const tuple& t = tuple::make(1,2,3, alloc); - BOOST_REQUIRE_EQUAL(3ul, t.size()); - BOOST_REQUIRE_EQUAL(1, t[0].to_long()); - BOOST_REQUIRE_EQUAL(2, t[1].to_long()); - BOOST_REQUIRE_EQUAL(3, t[2].to_long()); + BOOST_CHECK_EQUAL(3ul, t.size()); + BOOST_CHECK_EQUAL(1, t[0].to_long()); + BOOST_CHECK_EQUAL(2, t[1].to_long()); + BOOST_CHECK_EQUAL(3, t[2].to_long()); } { const tuple& t = tuple::make(1,2,3,4, alloc); - BOOST_REQUIRE_EQUAL(4ul, t.size()); - BOOST_REQUIRE_EQUAL(1, t[0].to_long()); - BOOST_REQUIRE_EQUAL(2, t[1].to_long()); - BOOST_REQUIRE_EQUAL(3, t[2].to_long()); - BOOST_REQUIRE_EQUAL(4, t[3].to_long()); + BOOST_CHECK_EQUAL(4ul, t.size()); + BOOST_CHECK_EQUAL(1, t[0].to_long()); + BOOST_CHECK_EQUAL(2, t[1].to_long()); + BOOST_CHECK_EQUAL(3, t[2].to_long()); + BOOST_CHECK_EQUAL(4, t[3].to_long()); } { const tuple& t = tuple::make(1,2,3,4,5, alloc); - BOOST_REQUIRE_EQUAL(5ul, t.size()); - BOOST_REQUIRE_EQUAL(1, t[0].to_long()); - BOOST_REQUIRE_EQUAL(2, t[1].to_long()); - BOOST_REQUIRE_EQUAL(3, t[2].to_long()); - BOOST_REQUIRE_EQUAL(4, t[3].to_long()); - BOOST_REQUIRE_EQUAL(5, t[4].to_long()); + BOOST_CHECK_EQUAL(5ul, t.size()); + BOOST_CHECK_EQUAL(1, t[0].to_long()); + BOOST_CHECK_EQUAL(2, t[1].to_long()); + BOOST_CHECK_EQUAL(3, t[2].to_long()); + BOOST_CHECK_EQUAL(4, t[3].to_long()); + BOOST_CHECK_EQUAL(5, t[4].to_long()); } { const tuple& t = tuple::make(1,2,3,4,5,6, alloc); - BOOST_REQUIRE_EQUAL(6ul, t.size()); - BOOST_REQUIRE_EQUAL(1, t[0].to_long()); - BOOST_REQUIRE_EQUAL(2, t[1].to_long()); - BOOST_REQUIRE_EQUAL(3, t[2].to_long()); - BOOST_REQUIRE_EQUAL(4, t[3].to_long()); - BOOST_REQUIRE_EQUAL(5, t[4].to_long()); - BOOST_REQUIRE_EQUAL(6, t[5].to_long()); + BOOST_CHECK_EQUAL(6ul, t.size()); + BOOST_CHECK_EQUAL(1, t[0].to_long()); + BOOST_CHECK_EQUAL(2, t[1].to_long()); + BOOST_CHECK_EQUAL(3, t[2].to_long()); + BOOST_CHECK_EQUAL(4, t[3].to_long()); + BOOST_CHECK_EQUAL(5, t[4].to_long()); + BOOST_CHECK_EQUAL(6, t[5].to_long()); } } @@ -717,14 +731,14 @@ BOOST_AUTO_TEST_CASE( test_trace ) eterm et4(tr4); trace tr5(1, 2, 3, epid("a@host",5,1,0,alloc), 6, alloc); eterm et5(tr5); - BOOST_REQUIRE(et1.initialized()); - BOOST_REQUIRE_EQUAL(TRACE, et1.type()); - BOOST_REQUIRE(et1 == et1); - BOOST_REQUIRE(et1 != et2); - BOOST_REQUIRE(et1 != et3); - BOOST_REQUIRE(et1 != et4); - BOOST_REQUIRE(et1 != et5); - BOOST_REQUIRE_EQUAL("{1,2,3,#Pid,4}", et1.to_string()); + BOOST_CHECK(et1.initialized()); + BOOST_CHECK_EQUAL(TRACE, et1.type()); + BOOST_CHECK(et1 == et1); + BOOST_CHECK(et1 != et2); + BOOST_CHECK(et1 != et3); + BOOST_CHECK(et1 != et4); + BOOST_CHECK(et1 != et5); + BOOST_CHECK_EQUAL("{1,2,3,#Pid,4}", et1.to_string()); } } @@ -742,9 +756,9 @@ BOOST_AUTO_TEST_CASE( test_varbind ) binding1.merge(binding2); - BOOST_REQUIRE_EQUAL(3ul, binding1.count()); - BOOST_REQUIRE(binding1[am_Name]); - BOOST_REQUIRE_EQUAL(eterm(20.0), binding1.get(am_Name)); + BOOST_CHECK_EQUAL(3ul, binding1.count()); + BOOST_CHECK(binding1[am_Name]); + BOOST_CHECK_EQUAL(eterm(20.0), binding1.get(am_Name)); #if __cplusplus >= 201103L EIXX_DECL_ATOM_VAR(am_a, "A"); @@ -779,32 +793,32 @@ BOOST_AUTO_TEST_CASE( test_assign ) { { eterm a = f(); - BOOST_REQUIRE_EQUAL(STRING, a.type()); - BOOST_REQUIRE_EQUAL("abcd", a.to_str()); + BOOST_CHECK_EQUAL(STRING, a.type()); + BOOST_CHECK_EQUAL("abcd", a.to_str()); } eterm a; { a.set( f() ); - BOOST_REQUIRE_EQUAL(STRING, a.type()); - BOOST_REQUIRE_EQUAL("abcd", a.to_str()); + BOOST_CHECK_EQUAL(STRING, a.type()); + BOOST_CHECK_EQUAL("abcd", a.to_str()); } { a = f(); - BOOST_REQUIRE_EQUAL(STRING, a.type()); - BOOST_REQUIRE_EQUAL("abcd", a.to_str()); + BOOST_CHECK_EQUAL(STRING, a.type()); + BOOST_CHECK_EQUAL("abcd", a.to_str()); } { eterm b("abcd"); eterm c = b; - BOOST_REQUIRE_EQUAL(STRING, c.type()); - BOOST_REQUIRE_EQUAL("abcd", c.to_str()); + BOOST_CHECK_EQUAL(STRING, c.type()); + BOOST_CHECK_EQUAL("abcd", c.to_str()); c = "ddd"; - BOOST_REQUIRE_EQUAL(STRING, c.type()); - BOOST_REQUIRE_EQUAL("ddd", c.to_str()); + BOOST_CHECK_EQUAL(STRING, c.type()); + BOOST_CHECK_EQUAL("ddd", c.to_str()); c.set( f() ); - BOOST_REQUIRE_EQUAL(STRING, c.type()); - BOOST_REQUIRE_EQUAL("abcd", c.to_str()); + BOOST_CHECK_EQUAL(STRING, c.type()); + BOOST_CHECK_EQUAL("abcd", c.to_str()); } } @@ -832,29 +846,29 @@ BOOST_AUTO_TEST_CASE( test_cast ) const list& l = ll[0].to_list(); const tuple& t = ll[1].to_tuple(); - BOOST_REQUIRE_EQUAL(true, t[0].to_bool()); - BOOST_REQUIRE_EQUAL(true, l.begin()->to_bool()); + BOOST_CHECK_EQUAL(true, t[0].to_bool()); + BOOST_CHECK_EQUAL(true, l.begin()->to_bool()); tuple et(ll, alloc); - BOOST_REQUIRE_EQUAL(sizeof(ll) / sizeof(eterm), et.size()); + BOOST_CHECK_EQUAL(sizeof(ll) / sizeof(eterm), et.size()); - BOOST_REQUIRE_EQUAL(1u, ll[0].to_list().length()); - BOOST_REQUIRE_EQUAL(1u, ll[1].to_tuple().size()); - BOOST_REQUIRE_EQUAL("test", ll[2].to_atom()); - BOOST_REQUIRE_EQUAL(123, ll[3].to_long()); - BOOST_REQUIRE_EQUAL(1.0, ll[4].to_double()); - BOOST_REQUIRE_EQUAL(true, ll[5].to_bool()); - BOOST_REQUIRE_EQUAL("ABC", ll[6].to_str()); + BOOST_CHECK_EQUAL(1u, ll[0].to_list().length()); + BOOST_CHECK_EQUAL(1u, ll[1].to_tuple().size()); + BOOST_CHECK_EQUAL("test", ll[2].to_atom()); + BOOST_CHECK_EQUAL(123, ll[3].to_long()); + BOOST_CHECK_EQUAL(1.0, ll[4].to_double()); + BOOST_CHECK_EQUAL(true, ll[5].to_bool()); + BOOST_CHECK_EQUAL("ABC", ll[6].to_str()); } } BOOST_AUTO_TEST_CASE( test_cast2 ) { allocator_t alloc; - { eterm t( eterm::cast(1) ); BOOST_REQUIRE_EQUAL(LONG, t.type()); } - { eterm t( eterm::cast(1.0) ); BOOST_REQUIRE_EQUAL(DOUBLE, t.type()); } - { eterm t( eterm::cast(true)); BOOST_REQUIRE_EQUAL(BOOL, t.type()); } - { eterm t( eterm::cast("ab")); BOOST_REQUIRE_EQUAL(STRING, t.type()); } + { eterm t( eterm::cast(1) ); BOOST_CHECK_EQUAL(LONG, t.type()); } + { eterm t( eterm::cast(1.0) ); BOOST_CHECK_EQUAL(DOUBLE, t.type()); } + { eterm t( eterm::cast(true)); BOOST_CHECK_EQUAL(BOOL, t.type()); } + { eterm t( eterm::cast("ab")); BOOST_CHECK_EQUAL(STRING, t.type()); } } diff --git a/test/test_eterm_encode.cpp b/test/test_eterm_encode.cpp index 3300c66..50712e7 100644 --- a/test/test_eterm_encode.cpp +++ b/test/test_eterm_encode.cpp @@ -156,11 +156,11 @@ BOOST_AUTO_TEST_CASE( test_encode_pid ) { { eterm t(epid("test@host", 1, 2, 0)); - BOOST_REQUIRE_EQUAL("#Pid", t.to_string()); + BOOST_REQUIRE_EQUAL("#Pid", t.to_string()); string s(t.encode(0)); //std::cout << s.to_binary_string() << std::endl; const uint8_t expect[] = - {131,103,ERL_ATOM_UTF8_EXT,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0,0,0,2,0}; + {131,88,118,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0,0,0,2,0,0,0,0}; BOOST_REQUIRE(s.equal(expect)); int idx = 1; // skipping the magic byte eterm pid(epid((const char*)expect, idx, sizeof(expect))); @@ -168,10 +168,10 @@ BOOST_AUTO_TEST_CASE( test_encode_pid ) } { const uint8_t expect[] = - {131,103,ERL_ATOM_UTF8_EXT,0,8,97,98,99,64,102,99,49,50,0,0,0,96,0,0,0,0,3}; + {131,88,118,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0,0,0,2,0,0,0,3}; int idx = 1; // skipping the magic byte epid decode_pid((const char*)expect, idx, sizeof(expect)); - epid expect_pid("abc@fc12", 96, 0, 3); + epid expect_pid("test@host", 1, 2, 3); BOOST_REQUIRE_EQUAL(expect_pid, decode_pid); } } @@ -197,16 +197,17 @@ BOOST_AUTO_TEST_CASE( test_encode_ref ) BOOST_REQUIRE_EQUAL("#Ref", t.to_string()); string s(t.encode(0)); //std::cout << s.to_binary_string() << std::endl; - const uint8_t expect[] = {131,114,0,3,ERL_ATOM_UTF8_EXT,0,9,116,101,115,116,64,104,111,115, - 116,0,0,0,0,1,0,0,0,2,0,0,0,3}; + const uint8_t expect[] = + {131,90,0,3,100,0,9,116,101,115,116,64,104,111,115,116,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3}; BOOST_REQUIRE(s.equal(expect)); int idx = 1; // skipping the magic byte ref t1((const char*)expect, idx, sizeof(expect)); BOOST_REQUIRE_EQUAL(eterm(t1), t); { ref t(atom("abc@fc12"), 993, 0, 0, 2); + //std::cout << string(eterm(t).encode(0)).to_binary_string() << std::endl; const uint8_t expect[] = - {131,114,0,3,ERL_ATOM_UTF8_EXT,0,8,97,98,99,64,102,99,49,50,2,0,0,3,225,0,0,0,0,0,0,0,0}; + {131,90,0,3,118,0,8,97,98,99,64,102,99,49,50,0,0,0,2,0,0,3,225,0,0,0,0,0,0,0,0}; int idx = 1; // skipping the magic byte ref t1((const char*)expect, idx, sizeof(expect)); BOOST_REQUIRE_EQUAL(t1, t); @@ -249,8 +250,8 @@ BOOST_AUTO_TEST_CASE( test_encode_trace ) eterm t(tr); string s(t.encode(0)); //std::cout << to_binary_string(s) << std::endl; - const uint8_t expect[] = {131,104,5,97,1,97,2,97,3,103,ERL_ATOM_UTF8_EXT,0,8,97,98,99,64, - 102,99,49,50,0,0,0,96,0,0,0,0,3,97,4}; + const uint8_t expect[] = + {131,104,5,97,1,97,2,97,3,88,118,0,8,97,98,99,64,102,99,49,50,0,0,0,96,0,0,0,0,0,0,0,3,97,4}; BOOST_REQUIRE(s.equal(expect)); int idx = 1; // skipping the magic byte trace t1((const char*)expect, idx, sizeof(expect)); @@ -260,18 +261,18 @@ BOOST_AUTO_TEST_CASE( test_encode_trace ) BOOST_REQUIRE_EQUAL(3, t1.serial()); BOOST_REQUIRE(self == t1.from()); BOOST_REQUIRE_EQUAL(4, t1.prev()); - BOOST_REQUIRE_EQUAL("{1,2,3,#Pid,4}", eterm(t1).to_string()); + BOOST_REQUIRE_EQUAL("{1,2,3,#Pid,4}", eterm(t1).to_string()); } BOOST_AUTO_TEST_CASE( test_encode_rpc ) { static const unsigned char s_expected[] = { - 131,104,2,103,100,0,14,69,67,71,46,72,49,46,48,48,49,64,102,49,54,0,0,0,1, - 0,0,0,0,0,104,5,100,0,4,99,97,108,108,100,0,7,101,99,103,95,97,112,105,100, - 0,11,114,101,103,95,112,114,111,99,101,115,115,108,0,0,0,5,100,0,3,69,67,71, - 100,0,10,69,67,71,46,72,49,46,48,48,49,103,100,0,14,69,67,71,46,72,49,46,48, - 48,49,64,102,49,54,0,0,0,1,0,0,0,0,0,107,0,12,101,120,97,109,112,108,101,95, - 99,111,114,101,98,0,0,7,208,106,100,0,4,117,115,101,114 + 131,104,2,88,118,0,14,69,67,71,46,72,49,46,48,48,49,64,102,49,54,0,0,0,1,0, + 0,0,0,0,0,0,0,104,5,118,0,4,99,97,108,108,118,0,7,101,99,103,95,97,112,105, + 118,0,11,114,101,103,95,112,114,111,99,101,115,115,108,0,0,0,5,118,0,3,69, + 67,71,118,0,10,69,67,71,46,72,49,46,48,48,49,88,118,0,14,69,67,71,46,72,49, + 46,48,48,49,64,102,49,54,0,0,0,1,0,0,0,0,0,0,0,0,107,0,12,101,120,97,109, + 112,108,101,95,99,111,114,101,98,0,0,7,208,106,118,0,4,117,115,101,114 }; epid l_pid("ECG.H1.001@f16", 1, 0, 0); From da5b2f0068cf65b3ada26a0b047c2659220d3935 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Tue, 24 Aug 2021 00:14:40 +0800 Subject: [PATCH 161/185] add version 6 handshake --- include/eixx/connect/basic_otp_connection.hpp | 4 +- .../eixx/connect/transport_otp_connection.hpp | 11 +- .../eixx/connect/transport_otp_connection.hxx | 3 +- .../connect/transport_otp_connection_tcp.hpp | 18 ++- .../connect/transport_otp_connection_tcp.hxx | 144 ++++++++++++++---- .../connect/transport_otp_connection_uds.hpp | 4 +- include/eixx/marshal/port.hxx | 29 +++- 7 files changed, 172 insertions(+), 41 deletions(-) diff --git a/include/eixx/connect/basic_otp_connection.hpp b/include/eixx/connect/basic_otp_connection.hpp index 023ada3..99cfedf 100644 --- a/include/eixx/connect/basic_otp_connection.hpp +++ b/include/eixx/connect/basic_otp_connection.hpp @@ -85,7 +85,7 @@ class basic_otp_connection BOOST_ASSERT(a_node != NULL); m_on_connect_status = h; m_transport = connection_type::create( - m_io_service, this, a_node->nodename(), + m_io_service, this, a_node->creation(), a_node->nodename(), a_remote_nodename, a_cookie, a_alloc); } @@ -110,7 +110,7 @@ class basic_otp_connection } m_transport = connection_type::create( - m_io_service, this, m_node->nodename(), + m_io_service, this, m_node->creation(), m_node->nodename(), m_remote_nodename, m_cookie, m_alloc); } diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index c765704..859c499 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -74,6 +74,7 @@ class connection connection_type m_type; atom m_remote_nodename; atom m_this_node; + uint32_t m_this_creation; atom m_cookie; Alloc m_allocator; @@ -233,10 +234,12 @@ class connection /// on_error() callback will be invoked on successful/failed connection /// status. /// @throws std::runtime_error - virtual void connect(atom a_this_node, - atom a_remote_nodename, - atom a_cookie) + virtual void connect(uint32_t a_this_creation, + atom a_this_node, + atom a_remote_nodename, + atom a_cookie) { + m_this_creation = a_this_creation; m_this_node = a_this_node; m_remote_nodename = a_remote_nodename; m_cookie = a_cookie; @@ -292,6 +295,7 @@ class connection static pointer create( boost::asio::io_service& a_svc, handler_type* a_h, + uint32_t a_this_creation, atom a_this_node, atom a_node, atom a_cookie, @@ -336,6 +340,7 @@ class connection virtual std::string peer_address() const { return ""; } atom remote_nodename() const { return m_remote_nodename; } atom local_nodename() const { return m_this_node; } + uint32_t local_creation() const { return m_this_creation; } atom cookie() const { return m_cookie; } Handler* handler() { return m_handler; } boost::asio::io_service& io_service() { return m_io_service; } diff --git a/include/eixx/connect/transport_otp_connection.hxx b/include/eixx/connect/transport_otp_connection.hxx index 4bccd55..19def05 100644 --- a/include/eixx/connect/transport_otp_connection.hxx +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -55,6 +55,7 @@ typename connection::pointer connection::create( boost::asio::io_service& a_svc, Handler* a_h, + uint32_t a_this_creation, atom a_this_node, atom a_node, atom a_cookie, @@ -86,7 +87,7 @@ connection::create( default: THROW_RUNTIME_ERROR("Not implemented! (proto=" << con_type << ')'); } - p->connect(a_this_node, a_node, a_cookie); + p->connect(a_this_creation, a_this_node, a_node, a_cookie); return p; } diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 8899b51..97bb003 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -49,17 +49,23 @@ namespace connect { #ifndef HAVE_EI_EPMD // These constants are not exposed by EI headers: +// See: https://github.com/erlang/otp/blob/OTP-24.0.5/lib/erl_interface/src/connect/ei_connect_int.h +typedef EI_ULONGLONG DistFlags; + static const int ERL_VERSION_MAGIC = 131; static const short EPMD_PORT = 4369; static const int EPMDBUF = 512; static const char EI_EPMD_PORT2_REQ = 122; static const char EI_EPMD_PORT2_RESP = 119; -static const char EI_DIST_HIGH = 5; +static const short EI_DIST_5 = 5; /* OTP R4 - 22 */ +static const short EI_DIST_6 = 6; /* OTP 23 and later */ +static const short EI_DIST_HIGH = EI_DIST_6; +static const short EI_DIST_LOW = EI_DIST_5; static const int DFLAG_PUBLISHED = 1; static const int DFLAG_ATOM_CACHE = 2; static const int DFLAG_EXTENDED_REFERENCES = 4; static const int DFLAG_DIST_MONITOR = 8; -static const int DFLAG_FUN_TAGS = 16; +static const int DFLAG_FUN_TAGS = 0x10; static const int DFLAG_NEW_FUN_TAGS = 0x80; static const int DFLAG_EXTENDED_PIDS_PORTS = 0x100; static const int DFLAG_EXPORT_PTR_TAG = 0x200; @@ -148,8 +154,14 @@ class tcp_connection uint32_t m_remote_challenge; uint32_t m_our_challenge; +#ifdef DistFlags + DistFlags m_remote_flags; +#else + unsigned int m_remote_flags; +#endif + /// @throws std::runtime_error - void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie); + void connect(uint32_t a_this_creation, atom a_this_node, atom a_remote_nodename, atom a_cookie); boost::shared_ptr > shared_from_this() { boost::shared_ptr > p = base_t::shared_from_this(); diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index 7173735..4306f39 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -54,6 +54,7 @@ void tcp_connection::start() template void tcp_connection::connect( + uint32_t a_this_creation, atom a_this_node, atom a_remote_node, atom a_cookie) { using boost::asio::ip::tcp; @@ -63,7 +64,7 @@ void tcp_connection::connect( if (a_remote_node.to_string().find('@') == std::string::npos) THROW_RUNTIME_ERROR("Invalid format of remote_node: " << a_remote_node); - base_t::connect(a_this_node, a_remote_node, a_cookie); + base_t::connect(a_this_creation, a_this_node, a_remote_node, a_cookie); //boost::system::error_code err = boost::asio::error::host_not_found; std::stringstream es; @@ -319,7 +320,53 @@ void tcp_connection::handle_connect(const boost::system::error_c m_our_challenge = gen_challenge(); // send challenge - size_t siz = 2 + 1 + 2 + 4 + this->m_this_node.size(); + // See: https://github.com/erlang/otp/blob/OTP-24.0.5/lib/erl_interface/src/connect/ei_connect.c#L2272-L2287 +#ifdef DistFlags + DistFlags flags = ( +#else + unsigned int flags = ( +#endif + DFLAG_EXTENDED_REFERENCES + | DFLAG_DIST_MONITOR + | DFLAG_EXTENDED_PIDS_PORTS + | DFLAG_FUN_TAGS + | DFLAG_NEW_FUN_TAGS + | DFLAG_NEW_FLOATS + | DFLAG_SMALL_ATOM_TAGS + | DFLAG_UTF8_ATOMS + | DFLAG_MAP_TAG + | DFLAG_BIG_CREATION + | DFLAG_EXPORT_PTR_TAG + | DFLAG_BIT_BINARIES +#ifdef DFLAG_HANDSHAKE_23 + | DFLAG_HANDSHAKE_23 +#endif +#ifdef DFLAG_V4_NC + | DFLAG_V4_NC +#endif +#ifdef DFLAG_UNLINK_ID + | DFLAG_UNLINK_ID +#endif + ); + +#ifdef EI_DIST_5 + char tag = (m_dist_version == EI_DIST_5) ? 'n' : 'N'; +#else + char tag = 'n'; +#endif +#ifdef DFLAG_NAME_ME + if (this->m_this_node.empty()) { + /* dynamic node name */ + tag = 'N'; /* presume ver 6 */ + flags |= DFLAG_NAME_ME; + } +#endif + + size_t siz; + if (tag == 'n') + siz = 2 + 1 + 2 + 4 + this->m_this_node.size(); + else /* tag == 'N' */ + siz = 2 + 1 + 8 + 4 + 2 + this->m_this_node.size(); if (siz > sizeof(m_buf_node)) { std::stringstream str; @@ -333,22 +380,19 @@ void tcp_connection::handle_connect(const boost::system::error_c char* w = m_buf_node; put16be(w, siz - 2); - put8(w, 'n'); - put16be(w, m_dist_version); - unsigned int flags = (DFLAG_EXTENDED_REFERENCES - | DFLAG_DIST_MONITOR - | DFLAG_EXTENDED_PIDS_PORTS - | DFLAG_FUN_TAGS - | DFLAG_NEW_FUN_TAGS - | DFLAG_NEW_FLOATS - | DFLAG_SMALL_ATOM_TAGS - | DFLAG_UTF8_ATOMS - | DFLAG_MAP_TAG - | DFLAG_BIG_CREATION - | DFLAG_EXPORT_PTR_TAG - | DFLAG_BIT_BINARIES - ); - put32be(w, flags); + put8(w, tag); + if (tag == 'n') { +#ifdef EI_DIST_5 + put16be(w, EI_DIST_5); /* spec demands ver==5 */ +#else + put16be(w, EI_DIST_LOW); /* spec demands ver==5 */ +#endif + put32be(w, flags); + } else { /* tag == 'N' */ + put64be(w, flags); + put32be(w, this->local_creation()); + put16be(w, this->local_nodename().size()); + } memcpy(w, this->local_nodename().c_str(), this->local_nodename().size()); if (this->handler()->verbose() >= VERBOSE_TRACE) { @@ -527,23 +571,71 @@ void tcp_connection::handle_read_challenge_body( BOOST_ASSERT(got_bytes >= (int)m_expect_size); char tag = get8(m_node_rd); - if (tag != 'n') { - std::stringstream str; str << "Error reading auth challenge tag '" - << this->remote_nodename() << "': " << tag; + if (tag != 'n' && tag != 'N') { + std::stringstream str; str << "<- RECV_CHALLENGE incorrect tag, " + << "expected 'n' or 'N', got '" << tag << "' from:" + << this->remote_nodename(); this->handler()->on_connect_failure(this, str.str()); boost::system::error_code ec; m_socket.close(ec); return; } - int version = get16be(m_node_rd); - int flags = get32be(m_node_rd); - m_remote_challenge = get32be(m_node_rd); + // See: https://github.com/erlang/otp/blob/OTP-24.0.5/lib/erl_interface/src/connect/ei_connect.c#L2478 + int version; + if (tag == 'n') { /* OLD */ + version = get16be(m_node_rd); +#ifdef EI_DIST_5 + if (version != EI_DIST_5) { + std::stringstream str; str << "<- RECV_CHALLENGE 'n' incorrect version=" + << version; + this->handler()->on_connect_failure(this, str.str()); + boost::system::error_code ec; + m_socket.close(ec); + return; + } +#endif + + m_remote_flags = get32be(m_node_rd); + m_remote_challenge = get32be(m_node_rd); + } else { /* NEW */ + version = EI_DIST_6; + m_remote_flags = get64be(m_node_rd); + m_remote_challenge = get32be(m_node_rd); + m_node_rd += 4; /* ignore peer 'creation' */ + } + + if (!(m_remote_flags & DFLAG_EXTENDED_REFERENCES)) { + std::stringstream str; str << "<- RECV_CHALLENGE peer cannot " + << "handle extended references"; + this->handler()->on_connect_failure(this, str.str()); + boost::system::error_code ec; + m_socket.close(ec); + return; + } + + if (!(m_remote_flags & DFLAG_EXTENDED_PIDS_PORTS)) { + std::stringstream str; str << "<- RECV_CHALLENGE peer cannot " + << "handle extended pids and ports"; + this->handler()->on_connect_failure(this, str.str()); + boost::system::error_code ec; + m_socket.close(ec); + return; + } + + if (!(m_remote_flags & DFLAG_NEW_FLOATS)) { + std::stringstream str; str << "<- RECV_CHALLENGE peer cannot " + << "handle binary float encoding"; + this->handler()->on_connect_failure(this, str.str()); + boost::system::error_code ec; + m_socket.close(ec); + return; + } if (this->handler()->verbose() >= VERBOSE_TRACE) { std::stringstream s; - s << "<- got auth challenge (version=" << version - << ", flags=" << flags << ", remote_challenge=" << m_remote_challenge << ')'; + s << "<- RECV_CHALLENGE (ok) version=" << version + << ", flags=" << m_remote_flags << ", challenge=" << m_remote_challenge; this->handler()->report_status(REPORT_INFO, s.str()); } diff --git a/include/eixx/connect/transport_otp_connection_uds.hpp b/include/eixx/connect/transport_otp_connection_uds.hpp index 065d777..2dd886a 100644 --- a/include/eixx/connect/transport_otp_connection_uds.hpp +++ b/include/eixx/connect/transport_otp_connection_uds.hpp @@ -88,9 +88,9 @@ class uds_connection std::string m_uds_filename; /// @throws std::runtime_error - void connect(atom a_this_node, atom a_remote_nodename, atom a_cookie) + void connect(uint32_t a_this_creation, atom a_this_node, atom a_remote_nodename, atom a_cookie) { - base_t::connect(a_this_node, a_remote_nodename, a_cookie); + base_t::connect(a_this_creation, a_this_node, a_remote_nodename, a_cookie); boost::system::error_code err; boost::asio::local::stream_protocol::endpoint endpoint(a_remote_nodename.to_string()); diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index 3e77a28..afa9041 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -38,9 +38,14 @@ port::port(const char *buf, int& idx, size_t size, const Alloc& a_alloc) const char* s = buf + idx; const char* s0 = s; auto tag = get8(s); - if (tag != ERL_PORT_EXT && - tag != ERL_NEW_PORT_EXT && - tag != ERL_V4_PORT_EXT) + if (tag != ERL_PORT_EXT +#ifdef ERL_NEW_PORT_EXT + && tag != ERL_NEW_PORT_EXT +#endif +#ifdef ERL_V4_PORT_EXT + && tag != ERL_V4_PORT_EXT +#endif + ) throw err_decode_exception("Error decoding port", idx, tag); int len = atom::get_len(s); @@ -54,14 +59,18 @@ port::port(const char *buf, int& idx, size_t size, const Alloc& a_alloc) uint32_t cre; switch (tag) { +#ifdef ERL_V4_PORT_EXT case ERL_V4_PORT_EXT: id = get64be(s); cre = get32be(s); break; +#endif +#ifdef ERL_NEW_PORT_EXT case ERL_NEW_PORT_EXT: id = uint64_t(get32be(s)); cre = get32be(s); break; +#endif case ERL_PORT_EXT: id = uint64_t(get32be(s)) & 0x0fffffff; /* 28 bits */ cre = get8(s) & 0x03; /* 2 bits */ @@ -86,15 +95,27 @@ void port::encode(char* buf, int& idx, size_t size) const memmove(s, str.c_str(), n); s += n; +#if defined(ERL_V4_PORT_EXT) && defined(ERL_NEW_PORT_EXT) if (id() > 0x0fffffff /* 28 bits */) { *s0 = ERL_V4_PORT_EXT; put64be(s, id()); put32be(s, creation()); + } else if (creation() > 0x03 /* 2 bits */) { +#elif defined(ERL_NEW_PORT_EXT) + if (creation() > 0x03 /* 2 bits */) { +#endif +#ifdef ERL_NEW_PORT_EXT + *s0 = ERL_NEW_PORT_EXT; + put32be(s, id()); + put32be(s, creation()); } else { +#endif *s0 = ERL_PORT_EXT; put32be(s, id()); - put32be(s, creation()); + put8(s, creation()); +#ifdef ERL_NEW_PORT_EXT } +#endif idx += s-s0; BOOST_ASSERT((size_t)idx <= size); From 1f3bea3ac77f753873f0e708b5b847513f45c5fa Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Tue, 24 Aug 2021 03:17:55 +0800 Subject: [PATCH 162/185] enable DFLAG_HANDSHAKE_23 and DFLAG_V4_NC --- .../eixx/connect/transport_otp_connection.hpp | 78 ++++ .../connect/transport_otp_connection_tcp.hpp | 49 +- .../connect/transport_otp_connection_tcp.hxx | 431 +++++++++++------- .../connect/transport_otp_connection_uds.hpp | 2 + include/eixx/marshal/atom.hpp | 26 +- include/eixx/marshal/eterm.hxx | 20 +- include/eixx/marshal/pid.hpp | 12 +- include/eixx/marshal/pid.hxx | 44 +- include/eixx/marshal/port.hpp | 6 +- include/eixx/marshal/port.hxx | 42 +- include/eixx/marshal/ref.hpp | 12 +- include/eixx/marshal/ref.hxx | 52 ++- include/eixx/util/atom_table.hpp | 11 +- 13 files changed, 498 insertions(+), 287 deletions(-) diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index 859c499..2016226 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -40,6 +40,55 @@ limitations under the License. #include #include +#ifdef HAVE_EI_EPMD +extern "C" { + +#include // see erl_interface/src +#include // ERL_VERSION_MAGIC +#include // see erl_interface/src + +} +#else +// These constants are not exposed by EI headers: +// See: https://github.com/erlang/otp/blob/OTP-24.0.5/lib/erl_interface/src/connect/ei_connect_int.h +#define ERL_VERSION_MAGIC 131 +#define EPMD_PORT 4369 +#define EPMDBUF 512 +#define EI_EPMD_PORT2_REQ 122 +#define EI_EPMD_PORT2_RESP 119 +#define EI_DIST_5 5 /* OTP R4 - 22 */ +#define EI_DIST_6 6 /* OTP 23 and later */ +#define EI_DIST_LOW EI_DIST_5 +#define EI_DIST_HIGH EI_DIST_6 +#define DFLAG_PUBLISHED 1 +#define DFLAG_ATOM_CACHE 2 +#define DFLAG_EXTENDED_REFERENCES 4 +#define DFLAG_DIST_MONITOR 8 +#define DFLAG_FUN_TAGS 0x10 +#define DFLAG_NEW_FUN_TAGS 0x80 +#define DFLAG_EXTENDED_PIDS_PORTS 0x100 +#define DFLAG_EXPORT_PTR_TAG 0x200 +#define DFLAG_BIT_BINARIES 0x400 +#define DFLAG_NEW_FLOATS 0x800 +#define DFLAG_SMALL_ATOM_TAGS 0x4000 +#define DFLAG_UTF8_ATOMS 0x10000 +#define DFLAG_MAP_TAG 0x20000 +#define DFLAG_BIG_CREATION 0x40000 +#define DFLAG_HANDSHAKE_23 0x1000000 +#define DFLAG_UNLINK_ID 0x2000000 + +/* + * As the old handshake only support 32 flag bits, we reserve the remaining + * bits in the lower 32 for changes in the handshake protocol or potentially + * new capabilities that we also want to backport to OTP-22 or older. + */ +typedef EI_ULONGLONG DistFlags; +#define DFLAG_RESERVED 0xfc000000 +#define DFLAG_NAME_ME (((DistFlags)0x2) << 32) +#define DFLAG_V4_NC (((DistFlags)0x4) << 32) + +#endif + namespace eixx { namespace connect { @@ -51,6 +100,34 @@ enum connection_type { UNDEFINED, TCP, UDS }; /// Convert connection type to string. const char* connection_type_to_str(connection_type a_type); +//------------------------------------------------------------------------------ +// capability flags supported by this class +//------------------------------------------------------------------------------ +// See: https://github.com/erlang/otp/blob/OTP-24.0.5/lib/erl_interface/src/connect/ei_connect.c#L2272-L2287 +inline constexpr uint64_t LOCAL_FLAGS = ( + DFLAG_EXTENDED_REFERENCES + | DFLAG_DIST_MONITOR + | DFLAG_EXTENDED_PIDS_PORTS + | DFLAG_FUN_TAGS + | DFLAG_NEW_FUN_TAGS + | DFLAG_NEW_FLOATS + | DFLAG_SMALL_ATOM_TAGS + | DFLAG_UTF8_ATOMS + | DFLAG_MAP_TAG + | DFLAG_BIG_CREATION + | DFLAG_EXPORT_PTR_TAG + | DFLAG_BIT_BINARIES +#ifdef DFLAG_HANDSHAKE_23 + | DFLAG_HANDSHAKE_23 +#endif +#ifdef DFLAG_V4_NC + | DFLAG_V4_NC +#endif +#ifdef DFLAG_UNLINK_ID + // | DFLAG_UNLINK_ID +#endif + ); + //---------------------------------------------------------------------------- // Base connection class. //---------------------------------------------------------------------------- @@ -335,6 +412,7 @@ class connection } virtual int native_socket() = 0; + virtual uint64_t remote_flags() const = 0; /// Address of connected peer. virtual std::string peer_address() const { return ""; } diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 97bb003..c618fb1 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -32,51 +32,13 @@ limitations under the License. #include #include +#ifdef HAVE_CONFIG_H #include - -#ifdef HAVE_EI_EPMD -extern "C" { - -#include // see erl_interface/src -#include // ERL_VERSION_MAGIC -#include // see erl_interface/src - -} #endif namespace eixx { namespace connect { -#ifndef HAVE_EI_EPMD -// These constants are not exposed by EI headers: -// See: https://github.com/erlang/otp/blob/OTP-24.0.5/lib/erl_interface/src/connect/ei_connect_int.h -typedef EI_ULONGLONG DistFlags; - -static const int ERL_VERSION_MAGIC = 131; -static const short EPMD_PORT = 4369; -static const int EPMDBUF = 512; -static const char EI_EPMD_PORT2_REQ = 122; -static const char EI_EPMD_PORT2_RESP = 119; -static const short EI_DIST_5 = 5; /* OTP R4 - 22 */ -static const short EI_DIST_6 = 6; /* OTP 23 and later */ -static const short EI_DIST_HIGH = EI_DIST_6; -static const short EI_DIST_LOW = EI_DIST_5; -static const int DFLAG_PUBLISHED = 1; -static const int DFLAG_ATOM_CACHE = 2; -static const int DFLAG_EXTENDED_REFERENCES = 4; -static const int DFLAG_DIST_MONITOR = 8; -static const int DFLAG_FUN_TAGS = 0x10; -static const int DFLAG_NEW_FUN_TAGS = 0x80; -static const int DFLAG_EXTENDED_PIDS_PORTS = 0x100; -static const int DFLAG_EXPORT_PTR_TAG = 0x200; -static const int DFLAG_BIT_BINARIES = 0x400; -static const int DFLAG_NEW_FLOATS = 0x800; -static const int DFLAG_SMALL_ATOM_TAGS = 0x4000; -static const int DFLAG_UTF8_ATOMS = 0x10000; -static const int DFLAG_MAP_TAG = 0x20000; -static const int DFLAG_BIG_CREATION = 0x40000; -#endif - //---------------------------------------------------------------------------- /// TCP connection channel //---------------------------------------------------------------------------- @@ -120,6 +82,8 @@ class tcp_connection #endif } + uint64_t remote_flags() const { return m_remote_flags; } + private: /// Authentication state enum connect_state { @@ -151,15 +115,10 @@ class tcp_connection const char* m_node_rd; char* m_node_wr; uint16_t m_dist_version; + uint64_t m_remote_flags; uint32_t m_remote_challenge; uint32_t m_our_challenge; -#ifdef DistFlags - DistFlags m_remote_flags; -#else - unsigned int m_remote_flags; -#endif - /// @throws std::runtime_error void connect(uint32_t a_this_creation, atom a_this_node, atom a_remote_nodename, atom a_cookie); diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index 4306f39..f3cb716 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -94,9 +94,10 @@ void tcp_connection::handle_resolve( { BOOST_ASSERT(m_state == CS_WAIT_RESOLVE); if (err) { - std::stringstream str; str << "Error resolving address of node '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "Error resolving address of node '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); return; } // Attempt a connection to the first endpoint in the list. Each endpoint @@ -125,10 +126,10 @@ void tcp_connection::handle_epmd_connect( strcpy(w, alivename.c_str()); if (this->handler()->verbose() >= VERBOSE_TRACE) { - std::stringstream s; - s << "-> sending epmd port req for '" << alivename << "': " - << to_binary_string(m_buf_epmd, len+2); - this->handler()->report_status(REPORT_INFO, s.str()); + std::stringstream ss; + ss << "-> sending epmd port req for '" << alivename << "': " + << to_binary_string(m_buf_epmd, len+2); + this->handler()->report_status(REPORT_INFO, ss.str()); } m_state = CS_WAIT_EPMD_WRITE_DONE; @@ -152,9 +153,10 @@ void tcp_connection::handle_epmd_connect( pthis->handle_epmd_connect(err, epnext); }); } else { - std::stringstream str; str << "Error connecting to epmd at host '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "Error connecting to epmd at host '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); } @@ -165,9 +167,10 @@ void tcp_connection::handle_epmd_write(const boost::system::erro { BOOST_ASSERT(m_state == CS_WAIT_EPMD_WRITE_DONE); if (err) { - std::stringstream str; str << "Error writing to epmd at host '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "Error writing to epmd at host '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -188,9 +191,10 @@ void tcp_connection::handle_epmd_read_header( { BOOST_ASSERT(m_state == CS_WAIT_EPMD_REPLY); if (err) { - std::stringstream str; str << "Error reading response from epmd at host '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "Error reading response from epmd at host '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -200,9 +204,10 @@ void tcp_connection::handle_epmd_read_header( int res = get8(s); if (res != EI_EPMD_PORT2_RESP) { // response type - std::stringstream str; str << "Error unknown response from epmd at host '" - << this->remote_nodename() << "': " << res; - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "Error unknown response from epmd at host '" + << this->remote_nodename() << "': " << res; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -211,16 +216,16 @@ void tcp_connection::handle_epmd_read_header( int n = get8(s); if (this->handler()->verbose() >= VERBOSE_TRACE) { - std::stringstream s; - s << "<- response from epmd: " << n - << " (" << (n ? "failed" : "ok") << ')'; - this->handler()->report_status(REPORT_INFO, s.str()); + std::stringstream ss; + ss << "<- response from epmd: " << n + << " (" << (n ? "failed" : "ok") << ')'; + this->handler()->report_status(REPORT_INFO, ss.str()); } if (n) { // Got negative response - std::stringstream str; - str << "Node " << this->remote_nodename() << " not known to epmd!"; - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "Node " << this->remote_nodename() << " not known to epmd!"; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -228,7 +233,7 @@ void tcp_connection::handle_epmd_read_header( m_epmd_wr = m_buf_epmd + bytes_transferred; - int need_bytes = 8 - (bytes_transferred - 2); + size_t need_bytes = 8 - (bytes_transferred - 2); if (need_bytes > 0) { boost::asio::async_read(m_socket, boost::asio::buffer(m_epmd_wr, sizeof(m_buf_epmd)-bytes_transferred), @@ -247,9 +252,10 @@ void tcp_connection::handle_epmd_read_body( { BOOST_ASSERT(m_state == CS_WAIT_EPMD_REPLY); if (err) { - std::stringstream str; str << "Error reading response body from epmd at host '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "Error reading response body from epmd at host '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -270,11 +276,11 @@ void tcp_connection::handle_epmd_read_body( m_dist_version = (dist_high > EI_DIST_HIGH ? EI_DIST_HIGH : dist_high); if (this->handler()->verbose() >= VERBOSE_TRACE) { - std::stringstream s; - s << "<- epmd returned: port=" << port << ",ntype=" << ntype - << ",proto=" << proto << ",dist_high=" << dist_high - << ",dist_low=" << dist_low; - this->handler()->report_status(REPORT_INFO, s.str()); + std::stringstream ss; + ss << "<- epmd returned: port=" << port << ",ntype=" << ntype + << ",proto=" << proto << ",dist_high=" << dist_high + << ",dist_low=" << dist_low; + this->handler()->report_status(REPORT_INFO, ss.str()); } m_peer_endpoint.port(port); @@ -283,9 +289,10 @@ void tcp_connection::handle_epmd_read_body( m_socket.close(ec); if (m_dist_version <= 4) { - std::stringstream str; str << "Incompatible version " << m_dist_version - << " of remote node '" << this->remote_nodename() << "'"; - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "Incompatible version " << m_dist_version + << " of remote node '" << this->remote_nodename() << "'"; + this->handler()->on_connect_failure(this, ss.str()); return; } @@ -302,60 +309,31 @@ void tcp_connection::handle_connect(const boost::system::error_c { BOOST_ASSERT(m_state == CS_WAIT_CONNECT); if (err) { - std::stringstream str; - str << "Cannot connect to node " << this->remote_nodename() - << " at port " << m_peer_endpoint.port() << ": " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "Cannot connect to node " << this->remote_nodename() + << " at port " << m_peer_endpoint.port() << ": " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; } if (this->handler()->verbose() >= VERBOSE_TRACE) { - std::stringstream s; - s << "<- Connected to node: " << this->remote_nodename(); - this->handler()->report_status(REPORT_INFO, s.str()); + std::stringstream ss; + ss << "<- TCP_OPEN (ok) from node '" << this->remote_nodename() << "'"; + this->handler()->report_status(REPORT_INFO, ss.str()); } m_our_challenge = gen_challenge(); - // send challenge - // See: https://github.com/erlang/otp/blob/OTP-24.0.5/lib/erl_interface/src/connect/ei_connect.c#L2272-L2287 -#ifdef DistFlags - DistFlags flags = ( -#else - unsigned int flags = ( -#endif - DFLAG_EXTENDED_REFERENCES - | DFLAG_DIST_MONITOR - | DFLAG_EXTENDED_PIDS_PORTS - | DFLAG_FUN_TAGS - | DFLAG_NEW_FUN_TAGS - | DFLAG_NEW_FLOATS - | DFLAG_SMALL_ATOM_TAGS - | DFLAG_UTF8_ATOMS - | DFLAG_MAP_TAG - | DFLAG_BIG_CREATION - | DFLAG_EXPORT_PTR_TAG - | DFLAG_BIT_BINARIES -#ifdef DFLAG_HANDSHAKE_23 - | DFLAG_HANDSHAKE_23 -#endif -#ifdef DFLAG_V4_NC - | DFLAG_V4_NC -#endif -#ifdef DFLAG_UNLINK_ID - | DFLAG_UNLINK_ID -#endif - ); - + auto flags = LOCAL_FLAGS; #ifdef EI_DIST_5 char tag = (m_dist_version == EI_DIST_5) ? 'n' : 'N'; #else char tag = 'n'; #endif #ifdef DFLAG_NAME_ME - if (this->m_this_node.empty()) { + if (this->local_nodename().empty()) { /* dynamic node name */ tag = 'N'; /* presume ver 6 */ flags |= DFLAG_NAME_ME; @@ -364,15 +342,15 @@ void tcp_connection::handle_connect(const boost::system::error_c size_t siz; if (tag == 'n') - siz = 2 + 1 + 2 + 4 + this->m_this_node.size(); + siz = 2 + 1 + 2 + 4 + this->local_nodename().size(); else /* tag == 'N' */ - siz = 2 + 1 + 8 + 4 + 2 + this->m_this_node.size(); + siz = 2 + 1 + 8 + 4 + 2 + this->local_nodename().size(); if (siz > sizeof(m_buf_node)) { - std::stringstream str; - str << "Node name too long: " << this->local_nodename() - << " [" << __FILE__ << ':' << __LINE__ << ']'; - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "-> SEND_NAME (error) nodename too long: " << this->local_nodename() + << " [" << __FILE__ << ':' << __LINE__ << ']'; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -383,8 +361,10 @@ void tcp_connection::handle_connect(const boost::system::error_c put8(w, tag); if (tag == 'n') { #ifdef EI_DIST_5 + m_dist_version = EI_DIST_5; put16be(w, EI_DIST_5); /* spec demands ver==5 */ #else + m_dist_version = EI_DIST_LOW; put16be(w, EI_DIST_LOW); /* spec demands ver==5 */ #endif put32be(w, flags); @@ -396,10 +376,11 @@ void tcp_connection::handle_connect(const boost::system::error_c memcpy(w, this->local_nodename().c_str(), this->local_nodename().size()); if (this->handler()->verbose() >= VERBOSE_TRACE) { - std::stringstream s; - s << "-> sending name " << siz << " bytes:" - << to_binary_string(m_buf_node, siz); - this->handler()->report_status(REPORT_INFO, s.str()); + std::stringstream ss; + ss << "-> SEND_NAME sending creation=" << this->local_creation() + << " to node '" << this->remote_nodename() << "': " + << to_binary_string(m_buf_node, siz); + this->handler()->report_status(REPORT_INFO, ss.str()); } m_state = CS_WAIT_WRITE_CHALLENGE_DONE; @@ -413,9 +394,10 @@ void tcp_connection::handle_write_name(const boost::system::erro { BOOST_ASSERT(m_state == CS_WAIT_WRITE_CHALLENGE_DONE); if (err) { - std::stringstream str; str << "Error writing auth challenge to node '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "-> SEND_NAME (error) sending name to node '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -434,21 +416,23 @@ void tcp_connection::handle_read_status_header( { BOOST_ASSERT(m_state == CS_WAIT_STATUS); if (err) { - std::stringstream str; str << "Error reading auth status from node '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_STATUS (error) reading status header from node '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; } m_node_rd = m_buf_node; - size_t len = get16be(m_node_rd); + m_expect_size = get16be(m_node_rd); - if (len != 3) { - std::stringstream str; str << "Node " << this->remote_nodename() - << " rejected connection with reason: " << std::string(m_node_rd, len); - this->handler()->on_connect_failure(this, str.str()); + if (m_expect_size > (size_t)MAXNODELEN + 8 || m_expect_size > (size_t)((m_buf_node+1) - m_node_rd)) { + std::stringstream ss; + ss << "<- RECV_STATUS (error) in status length from node '" + << this->remote_nodename() << "': " << m_expect_size; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -456,7 +440,8 @@ void tcp_connection::handle_read_status_header( m_node_wr = m_buf_node + bytes_transferred; - int need_bytes = 5 - (bytes_transferred - 2); + size_t need_bytes = m_expect_size - (m_node_wr - m_node_rd); + // size_t need_bytes = 5 - (bytes_transferred - 2); if (need_bytes > 0) { boost::asio::async_read(m_socket, boost::asio::buffer(m_node_wr, (m_buf_node+1) - m_node_wr), @@ -475,9 +460,10 @@ void tcp_connection::handle_read_status_body( { BOOST_ASSERT(m_state == CS_WAIT_STATUS); if (err) { - std::stringstream str; str << "Error reading auth status body from node '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_STATUS (error) reading status body from node '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -487,13 +473,51 @@ void tcp_connection::handle_read_status_body( int got_bytes = m_node_wr - m_node_rd; BOOST_ASSERT(got_bytes >= 3); - if (memcmp(m_node_rd, "sok", 3) != 0) { - std::stringstream str; str << "Error invalid auth status response '" - << this->remote_nodename() << "': " << std::string(m_node_rd, 3); - this->handler()->on_connect_failure(this, str.str()); - boost::system::error_code ec; - m_socket.close(ec); - return; + if (!this->local_nodename().empty()) { + if (memcmp(m_node_rd, "sok", 3) != 0) { + std::stringstream ss; + ss << "<- RECV_STATUS (error) in auth status from node '" + << this->remote_nodename() << "': " << std::string(m_node_rd, 1, got_bytes); + this->handler()->on_connect_failure(this, ss.str()); + boost::system::error_code ec; + m_socket.close(ec); + return; + } + } else { + /* dynamic node name */ + if (memcmp(m_node_rd, "snamed:", 7) != 0) { + std::stringstream ss; + ss << "<- RECV_STATUS (error) in auth status from node '" + << this->remote_nodename() << "': " << std::string(m_node_rd, 1, got_bytes); + this->handler()->on_connect_failure(this, ss.str()); + boost::system::error_code ec; + m_socket.close(ec); + return; + } + + uint16_t nodename_len = get16be(m_node_rd); + if (nodename_len > MAXNODELEN) { + std::stringstream ss; + ss << "<- RECV_STATUS (error) nodename too long from node '" + << this->remote_nodename() << "': " << nodename_len; + this->handler()->on_connect_failure(this, ss.str()); + boost::system::error_code ec; + m_socket.close(ec); + return; + } + atom l_this_node(m_node_rd, nodename_len); + this->m_this_node = l_this_node; + + uint32_t l_cre = get32be(m_node_rd); + this->m_this_creation = l_cre; + } + + if (this->handler()->verbose() >= VERBOSE_TRACE) { + std::stringstream ss; + ss << "<- RECV_STATUS (ok) from node '" << this->remote_nodename() + << "': version=" << m_dist_version + << ", status=" << std::string(m_node_rd, 1, got_bytes); + this->handler()->report_status(REPORT_INFO, ss.str()); } m_state = CS_WAIT_CHALLENGE; @@ -517,9 +541,10 @@ void tcp_connection::handle_read_challenge_header( { BOOST_ASSERT(m_state == CS_WAIT_CHALLENGE); if (err) { - std::stringstream str; str << "Error reading auth challenge from node '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE (error) reading challenge header from node '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -527,11 +552,17 @@ void tcp_connection::handle_read_challenge_header( m_node_wr += bytes_transferred; m_expect_size = get16be(m_node_rd); +#ifdef EI_DIST_5 + unsigned short l_size = (m_dist_version == EI_DIST_5) ? 11 : 19; +#else + unsigned short l_size = 11; +#endif - if ((m_expect_size - 11) > (size_t)MAXNODELEN || m_expect_size > (size_t)((m_buf_node+1)-m_node_rd)) { - std::stringstream str; str << "Error in auth status challenge node length " - << this->remote_nodename() << " : " << m_expect_size; - this->handler()->on_connect_failure(this, str.str()); + if (m_expect_size > (size_t)MAXNODELEN + l_size || m_expect_size > (size_t)((m_buf_node+1) - m_node_rd)) { + std::stringstream ss; + ss << "<- RECV_CHALLENGE (error) in challenge length from node '" + << this->remote_nodename() << "': " << m_expect_size; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -556,9 +587,10 @@ void tcp_connection::handle_read_challenge_body( { BOOST_ASSERT(m_state == CS_WAIT_CHALLENGE); if (err) { - std::stringstream str; str << "Error reading auth challenge body from node '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE (error) reading challenge body from node '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -572,24 +604,28 @@ void tcp_connection::handle_read_challenge_body( char tag = get8(m_node_rd); if (tag != 'n' && tag != 'N') { - std::stringstream str; str << "<- RECV_CHALLENGE incorrect tag, " - << "expected 'n' or 'N', got '" << tag << "' from:" - << this->remote_nodename(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE (error) incorrect tag, " + << "expected 'n' or 'N', got '" << tag << "' from node '" + << this->remote_nodename() << "'"; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; } + size_t nodename_len; + uint16_t l_dist_version = m_dist_version; + // See: https://github.com/erlang/otp/blob/OTP-24.0.5/lib/erl_interface/src/connect/ei_connect.c#L2478 - int version; if (tag == 'n') { /* OLD */ - version = get16be(m_node_rd); + m_dist_version = get16be(m_node_rd); #ifdef EI_DIST_5 - if (version != EI_DIST_5) { - std::stringstream str; str << "<- RECV_CHALLENGE 'n' incorrect version=" - << version; - this->handler()->on_connect_failure(this, str.str()); + if (m_dist_version != EI_DIST_5) { + std::stringstream ss; + ss << "<- RECV_CHALLENGE 'n' (error) incorrect version from node '" + << this->remote_nodename() << "': " << m_dist_version; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -598,63 +634,100 @@ void tcp_connection::handle_read_challenge_body( m_remote_flags = get32be(m_node_rd); m_remote_challenge = get32be(m_node_rd); + nodename_len = m_node_wr - m_node_rd; +#ifndef EI_DIST_6 + } +#else } else { /* NEW */ - version = EI_DIST_6; + m_dist_version = EI_DIST_6; m_remote_flags = get64be(m_node_rd); m_remote_challenge = get32be(m_node_rd); - m_node_rd += 4; /* ignore peer 'creation' */ + m_node_rd += 4; /* ignore peer 'creation' */ + nodename_len = get16be(m_node_rd); + + if (nodename_len > m_node_wr - m_node_rd) { + std::stringstream ss; + ss << "<- RECV_CHALLENGE 'N' (error) nodename too long from node '" + << this->remote_nodename() << "': " << nodename_len; + this->handler()->on_connect_failure(this, ss.str()); + boost::system::error_code ec; + m_socket.close(ec); + return; + } + } +#endif + + if (nodename_len > MAXNODELEN) { + std::stringstream ss; + ss << "<- RECV_CHALLENGE (error) nodename too long from node '" + << this->remote_nodename() << "': " << nodename_len; + this->handler()->on_connect_failure(this, ss.str()); + boost::system::error_code ec; + m_socket.close(ec); + return; } if (!(m_remote_flags & DFLAG_EXTENDED_REFERENCES)) { - std::stringstream str; str << "<- RECV_CHALLENGE peer cannot " - << "handle extended references"; - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE peer cannot handle extended references"; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; } if (!(m_remote_flags & DFLAG_EXTENDED_PIDS_PORTS)) { - std::stringstream str; str << "<- RECV_CHALLENGE peer cannot " - << "handle extended pids and ports"; - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE peer cannot handle extended pids and ports"; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; } if (!(m_remote_flags & DFLAG_NEW_FLOATS)) { - std::stringstream str; str << "<- RECV_CHALLENGE peer cannot " - << "handle binary float encoding"; - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE peer cannot handle binary float encoding"; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; } if (this->handler()->verbose() >= VERBOSE_TRACE) { - std::stringstream s; - s << "<- RECV_CHALLENGE (ok) version=" << version - << ", flags=" << m_remote_flags << ", challenge=" << m_remote_challenge; - this->handler()->report_status(REPORT_INFO, s.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE (ok) version=" << m_dist_version + << ", flags=" << m_remote_flags << ", challenge=" << m_remote_challenge; + this->handler()->report_status(REPORT_INFO, ss.str()); } uint8_t our_digest[16]; gen_digest(m_remote_challenge, this->m_cookie.c_str(), our_digest); - // send challenge reply - int siz = 2 + 1 + 4 + 16; char* w = m_buf_node; - put16be(w,siz - 2); + int siz = 0; + + // send complement (if dist_version upgraded in-flight) + if (m_dist_version > l_dist_version) { + siz += 2 + 1 + 4 + 4; + put16be(w, 9); + put8(w, 'c'); + put32be(w, LOCAL_FLAGS >> 32 /* FlagsHigh */); + put32be(w, this->local_creation()); + } + + // send challenge reply + siz += 2 + 1 + 4 + 16; + put16be(w, 21); put8(w, 'r'); put32be(w, m_our_challenge); memcpy (w, our_digest, 16); if (this->handler()->verbose() >= VERBOSE_TRACE) { - std::stringstream s; - s << "-> sending challenge reply " << siz << " bytes:" - << to_binary_string(m_buf_node, siz); - this->handler()->report_status(REPORT_INFO, s.str()); + std::stringstream ss; + ss << "-> SEND_CHALLENGE_REPLY sending " << siz << " bytes: " + << to_binary_string(m_buf_node, siz); + this->handler()->report_status(REPORT_INFO, ss.str()); } m_state = CS_WAIT_WRITE_CHALLENGE_REPLY_DONE; @@ -668,9 +741,10 @@ void tcp_connection::handle_write_challenge_reply(const boost::s { BOOST_ASSERT(m_state == CS_WAIT_WRITE_CHALLENGE_REPLY_DONE); if (err) { - std::stringstream str; str << "Error writing auth challenge reply to node '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "-> SEND_CHALLENGE_REPLY (error) sending reply to node '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -689,10 +763,11 @@ void tcp_connection::handle_read_challenge_ack_header( { BOOST_ASSERT(m_state == CS_WAIT_CHALLENGE_ACK); if (err) { - std::stringstream str; str << "Error reading auth challenge ack from node '" - << this->remote_nodename() << "': " - << (err == boost::asio::error::eof ? "Possibly bad cookie?" : err.message()); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE_ACK (error) reading ack header from node '" + << this->remote_nodename() << "': " + << (err == boost::asio::error::eof ? "Possibly bad cookie?" : err.message()); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -701,10 +776,11 @@ void tcp_connection::handle_read_challenge_ack_header( m_node_rd = m_buf_node; m_expect_size = get16be(m_node_rd); - if (m_expect_size > sizeof(m_buf_node)-2) { - std::stringstream str; str << "Error in auth status challenge ack length " - << this->remote_nodename() << " : " << m_expect_size; - this->handler()->on_connect_failure(this, str.str()); + if (m_expect_size > sizeof(m_buf_node) - 2) { + std::stringstream ss; + ss << "<- RECV_CHALLENGE_ACK (error) in ack length from node '" + << this->remote_nodename() << "': " << m_expect_size; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -732,9 +808,10 @@ void tcp_connection::handle_read_challenge_ack_body( { BOOST_ASSERT(m_state == CS_WAIT_CHALLENGE_ACK); if (err) { - std::stringstream str; str << "Error reading auth challenge ack body from node '" - << this->remote_nodename() << "': " << err.message(); - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE_ACK (error) reading ack body from node '" + << this->remote_nodename() << "': " << err.message(); + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -742,22 +819,23 @@ void tcp_connection::handle_read_challenge_ack_body( m_node_wr += bytes_transferred; #ifndef NDEBUG - int got_bytes = m_node_wr - m_node_rd; + size_t got_bytes = m_node_wr - m_node_rd; #endif - BOOST_ASSERT(got_bytes >= (int)m_expect_size); + BOOST_ASSERT(got_bytes >= m_expect_size); char tag = get8(m_node_rd); if (this->handler()->verbose() >= VERBOSE_TRACE) { - std::stringstream s; - s << "<- got auth challenge ack (tag=" << tag << "): " - << to_binary_string(m_node_rd, m_expect_size-1); - this->handler()->report_status(REPORT_INFO, s.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE_ACK received (tag=" << tag << "): " + << to_binary_string(m_node_rd, m_expect_size-1); + this->handler()->report_status(REPORT_INFO, ss.str()); } if (tag != 'a') { - std::stringstream str; str << "Error reading auth challenge ack body tag '" - << this->remote_nodename() << "': " << tag; - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE_ACK incorrect tag from '" + << this->remote_nodename() << "', expected 'a' got '" << tag << "'"; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; @@ -767,9 +845,10 @@ void tcp_connection::handle_read_challenge_ack_body( memcpy(her_digest, m_node_rd, 16); gen_digest(m_our_challenge, this->m_cookie.c_str(), (uint8_t*)expected_digest); if (memcmp(her_digest, expected_digest, 16) != 0) { - std::stringstream str; str << "Authentication failure at node '" - << this->remote_nodename() << '!'; - this->handler()->on_connect_failure(this, str.str()); + std::stringstream ss; + ss << "<- RECV_CHALLENGE_ACK authorization failure for node '" + << this->remote_nodename() << "'!"; + this->handler()->on_connect_failure(this, ss.str()); boost::system::error_code ec; m_socket.close(ec); return; diff --git a/include/eixx/connect/transport_otp_connection_uds.hpp b/include/eixx/connect/transport_otp_connection_uds.hpp index 2dd886a..621eeda 100644 --- a/include/eixx/connect/transport_otp_connection_uds.hpp +++ b/include/eixx/connect/transport_otp_connection_uds.hpp @@ -82,6 +82,8 @@ class uds_connection #endif } + uint64_t remote_flags() const { return 0; } + private: /// Socket for the connection. boost::asio::local::stream_protocol::socket m_socket; diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index d9dd727..9e668e5 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -60,8 +60,8 @@ namespace detail { /** * Provides a representation of Erlang atoms. Atoms can be - * created from strings whose length is not more than - * MAXATOMLEN characters. + * created from UTF8 strings whose length is not more than + * MAXATOMLEN characters / codepoints. */ class atom { @@ -88,7 +88,7 @@ class atom /// Create an atom from the given string. /// @param atom the string to create the atom from. /// @throw std::runtime_error if atom table is full. - /// @throw err_bad_argument if atom size is longer than MAXATOMLEN + /// @throw err_bad_argument if atom length is longer than MAXATOMLEN atom(const char* s) : m_index(atom_table().lookup(std::string(s))) {} @@ -209,7 +209,10 @@ class atom /// Get the size of a buffer needed to encode this atom in /// the external binary format. - size_t encode_size() const { return 3 + length(); } + size_t encode_size() const { + const size_t len = length(); + return (len > 255 ? 3 : 2) + len; + } /// Encode the atom in external binary format. /// @param buf is the buffer space to encode the atom to. @@ -218,11 +221,16 @@ class atom void encode(char* buf, int& idx, size_t size) const { char* s = buf + idx; char* s0 = s; - const int len = std::min((size_t)MAXATOMLEN, length()); - /* This function is documented to truncate at MAXATOMLEN (256) */ - put8(s,ERL_ATOM_UTF8_EXT); - put16be(s,len); - memmove(s,c_str(),len); /* unterminated string */ + const size_t len = std::min((size_t)MAXATOMLEN_UTF8, length()); + /* This function is documented to truncate at MAXATOMLEN_UTF8 (1021) */ + if (len > 255) { + put8(s, ERL_ATOM_UTF8_EXT); + put16be(s, len); + } else { + put8(s, ERL_SMALL_ATOM_UTF8_EXT); + put8(s, len); + } + memmove(s, c_str(), len); /* unterminated string */ s += len; idx += s-s0; BOOST_ASSERT((size_t)idx <= size); diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index f640aae..a6315d0 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -239,12 +239,12 @@ void eterm::decode(const char* a_buf, int& idx, size_t a_size, const Allo throw err_decode_exception("Cannot determine term type", idx); switch (type) { -#ifdef ERL_ATOM_UTF8_EXT - case ERL_ATOM_UTF8_EXT: -#endif #ifdef ERL_SMALL_ATOM_UTF8_EXT case ERL_SMALL_ATOM_UTF8_EXT: #endif +#ifdef ERL_ATOM_UTF8_EXT + case ERL_ATOM_UTF8_EXT: +#endif #ifdef ERL_SMALL_ATOM_EXT case ERL_SMALL_ATOM_EXT: #endif @@ -291,19 +291,31 @@ void eterm::decode(const char* a_buf, int& idx, size_t a_size, const Allo new (this) eterm(d); break; } + case ERL_BINARY_EXT: new (this) eterm(binary(a_buf, idx, a_size, a_alloc)); break; +#ifdef ERL_NEW_PID_EXT + case ERL_NEW_PID_EXT: +#endif case ERL_PID_EXT: new (this) eterm(epid(a_buf, idx, a_size, a_alloc)); break; - case ERL_REFERENCE_EXT: +#ifdef ERL_NEWER_REFERENCE_EXT + case ERL_NEWER_REFERENCE_EXT: +#endif +#ifdef ERL_NEW_REFERENCE_EXT case ERL_NEW_REFERENCE_EXT: +#endif + case ERL_REFERENCE_EXT: new (this) eterm(ref(a_buf, idx, a_size, a_alloc)); break; +#ifdef ERL_NEW_PORT_EXT + case ERL_NEW_PORT_EXT: +#endif case ERL_PORT_EXT: new (this) eterm(port(a_buf, idx, a_size, a_alloc)); break; diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index 734500a..31d9543 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -78,7 +78,7 @@ class epid { } // Must only be called from constructor! - void init(const atom& node, int id, int serial, int creation, const Alloc& alloc) + void init(const atom& node, int id, int serial, uint32_t creation, const Alloc& alloc) { m_blob = new blob(1, alloc); new (m_blob->data()) pid_blob(node, id, serial, creation); @@ -110,15 +110,15 @@ class epid { * @param a_alloc is the allocator to use. * @throw err_bad_argument if node is empty or greater than MAX_NODE_LENGTH **/ - epid(const char* node, int id, int serial, int creation, const Alloc& a_alloc = Alloc()) + epid(const char* node, int id, int serial, uint32_t creation, const Alloc& a_alloc = Alloc()) : epid(atom(node), id, serial, creation, a_alloc) {} - epid(const atom& node, int id, int creation, const Alloc& a_alloc = Alloc()) + epid(const atom& node, int id, uint32_t creation, const Alloc& a_alloc = Alloc()) : epid(node, id, 0, creation, a_alloc) {} - epid(const atom& node, int id, int serial, int creation, const Alloc& a_alloc = Alloc()) + epid(const atom& node, int id, int serial, uint32_t creation, const Alloc& a_alloc = Alloc()) { detail::check_node_length(node.size()); init(node, id, serial, creation, a_alloc); @@ -184,7 +184,7 @@ class epid { * Get the creation number from the PID. * @return the creation number from the PID. **/ - int creation() const { return m_blob ? m_blob->data()->creation : 0; } + uint32_t creation() const { return m_blob ? m_blob->data()->creation : 0; } uint32_t id_internal() const { return m_blob ? m_blob->data()->id : 0; } @@ -205,7 +205,7 @@ class epid { if (creation() < t2.creation()) return true; return false; } - size_t encode_size() const { return 16 + node().size(); } + size_t encode_size() const { return (creation() > 0x03 ? 16 : 13) + node().size(); } void encode(char* buf, int& idx, size_t size) const; diff --git a/include/eixx/marshal/pid.hxx b/include/eixx/marshal/pid.hxx index 9d3ca23..1a786a1 100644 --- a/include/eixx/marshal/pid.hxx +++ b/include/eixx/marshal/pid.hxx @@ -38,7 +38,11 @@ void epid::decode(const char *buf, int& idx, size_t size, const Alloc& al const char* s = buf + idx; const char* s0 = s; auto n = get8(s); - if (n != ERL_PID_EXT && n != ERL_NEW_PID_EXT) + if (n != ERL_PID_EXT +#ifdef ERL_NEW_PID_EXT + && n != ERL_NEW_PID_EXT +#endif + ) throw err_decode_exception("Error decoding pid", n); int len = atom::get_len(s); @@ -49,9 +53,13 @@ void epid::decode(const char *buf, int& idx, size_t size, const Alloc& al atom l_node(s, len); s += len; - uint32_t l_id = get32be(s); - uint32_t l_ser = get32be(s); + uint32_t l_id = get32be(s); /* 15 bits if distribution flag DFLAG_V4_NC is not set */ + uint32_t l_ser = get32be(s); /* 13 bits if distribution flag DFLAG_V4_NC is not set */ +#ifdef ERL_NEW_PID_EXT uint32_t l_cre = n == ERL_NEW_PID_EXT ? get32be(s) : (get8(s) & 0x03); +#else + uint32_t l_cre = get8(s) & 0x03; /* 2 bits */ +#endif init(l_node, l_id, l_ser, l_cre, alloc); @@ -64,18 +72,36 @@ void epid::encode(char* buf, int& idx, size_t size) const { char* s = buf + idx; char* s0 = s; - put8(s,ERL_NEW_PID_EXT); - put8(s,ERL_ATOM_UTF8_EXT); + s++; // Skip ERL_PID_EXT + + /* the nodename */ +#ifdef ERL_ATOM_UTF8_EXT + put8(s, ERL_ATOM_UTF8_EXT); +#else + put8(s, ERL_ATOM_EXT); +#endif const std::string& nd = node().to_string(); unsigned short n = nd.size(); put16be(s, n); memmove(s, nd.c_str(), n); s += n; - /* now the integers */ - put32be(s, id()); /* 15 bits */ - put32be(s, serial()); /* 13 bits */ - put32be(s, creation()); /* 2 bits */ + /* the integers */ + put32be(s, id()); /* 15 bits if distribution flag DFLAG_V4_NC is not set */ + put32be(s, serial()); /* 13 bits if distribution flag DFLAG_V4_NC is not set */ + const uint32_t l_cre = creation(); +#ifdef ERL_NEW_PID_EXT + if (l_cre > 0x03 /* 2 bits */) { + *s0 = ERL_NEW_PID_EXT; + put32be(s, l_cre); + } else { + *s0 = ERL_PID_EXT; + put8(s, l_cre & 0x03 /* 2 bits */); + } +#else + *s0 = ERL_PID_EXT; + put8(s, l_cre & 0x03 /* 2 bits */); +#endif idx += s-s0; BOOST_ASSERT((size_t)idx <= size); diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index 25bdf59..77b9f19 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -85,7 +85,7 @@ class port { * 2 bits will be used. * @throw err_bad_argument if node is empty or greater than MAX_NODE_LENGTH **/ - port(const char* node, const int id, const int creation, const Alloc& a_alloc = Alloc()) + port(const char* node, const int id, const uint32_t creation, const Alloc& a_alloc = Alloc()) { size_t n = strlen(node); detail::check_node_length(n); @@ -93,7 +93,7 @@ class port { init(l_node, id, creation, a_alloc); } - port(const atom& node, const int id, const int creation, const Alloc& a_alloc = Alloc()) + port(const atom& node, const int id, const uint32_t creation, const Alloc& a_alloc = Alloc()) { detail::check_node_length(node.size()); init(node, id, creation, a_alloc); @@ -163,7 +163,7 @@ class port { return false; } - size_t encode_size() const { return (id() > 0x0fffffff ? 16 : 12) + node().size(); } + size_t encode_size() const { return (id() > 0x0fffffff ? 16 : creation() > 0x03 ? 12 : 9) + node().size(); } void encode(char* buf, int& idx, size_t size) const; diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index afa9041..3eb76df 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -67,12 +67,12 @@ port::port(const char *buf, int& idx, size_t size, const Alloc& a_alloc) #endif #ifdef ERL_NEW_PORT_EXT case ERL_NEW_PORT_EXT: - id = uint64_t(get32be(s)); + id = uint64_t(get32be(s) & 0x0fffffff); /* 28 bits */ cre = get32be(s); break; #endif case ERL_PORT_EXT: - id = uint64_t(get32be(s)) & 0x0fffffff; /* 28 bits */ + id = uint64_t(get32be(s) & 0x0fffffff); /* 28 bits */ cre = get8(s) & 0x03; /* 2 bits */ break; } @@ -88,32 +88,46 @@ void port::encode(char* buf, int& idx, size_t size) const char* s = buf + idx; char* s0 = s; s++; // Skip ERL_PORT_EXT - put8(s,ERL_ATOM_UTF8_EXT); + + /* the nodename */ +#ifdef ERL_ATOM_UTF8_EXT + put8(s, ERL_ATOM_UTF8_EXT); +#else + put8(s, ERL_ATOM_EXT); +#endif const std::string& str = node().to_string(); unsigned short n = str.size(); put16be(s, n); memmove(s, str.c_str(), n); s += n; -#if defined(ERL_V4_PORT_EXT) && defined(ERL_NEW_PORT_EXT) + /* the integers */ + const uint32_t l_cre = creation(); +#if defined(ERL_V4_PORT_EXT) if (id() > 0x0fffffff /* 28 bits */) { *s0 = ERL_V4_PORT_EXT; put64be(s, id()); - put32be(s, creation()); - } else if (creation() > 0x03 /* 2 bits */) { + put32be(s, l_cre); + + #ifdef ERL_NEW_PORT_EXT + } else if (l_cre > 0x03 /* 2 bits */) { + *s0 = ERL_NEW_PORT_EXT; + put32be(s, id() & 0x0fffffff /* 28 bits */); + put32be(s, l_cre); + #else + } else { + #endif #elif defined(ERL_NEW_PORT_EXT) - if (creation() > 0x03 /* 2 bits */) { -#endif -#ifdef ERL_NEW_PORT_EXT + if (l_cre > 0x03 /* 2 bits */) { *s0 = ERL_NEW_PORT_EXT; - put32be(s, id()); - put32be(s, creation()); + put32be(s, id() & 0x0fffffff /* 28 bits */); + put32be(s, l_cre); } else { #endif *s0 = ERL_PORT_EXT; - put32be(s, id()); - put8(s, creation()); -#ifdef ERL_NEW_PORT_EXT + put32be(s, id() & 0x0fffffff /* 28 bits */); + put8(s, l_cre); +#if defined(ERL_V4_PORT_EXT) || defined(ERL_NEW_PORT_EXT) } #endif diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index 4cfd818..fb44088 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -47,7 +47,7 @@ namespace detail { */ template class ref { - enum { COUNT = 5 }; + enum { COUNT = 5 /* max of 5 when the DFLAG_V4_NC has been set */ }; struct ref_blob { atom node; @@ -120,21 +120,21 @@ class ref { * 2 bits will be used. * @throw err_bad_argument if node is empty or greater than MAX_NODE_LENGTH */ - ref(const atom& node, const uint32_t* a_ids, size_t n, unsigned int creation, + ref(const atom& node, const uint32_t* a_ids, size_t n, uint32_t creation, const Alloc& a_alloc = Alloc()) { init(node, a_ids, n, creation, a_alloc); } template - ref(const atom& node, uint32_t (&ids)[N], unsigned int creation, + ref(const atom& node, uint32_t (&ids)[N], uint32_t creation, const Alloc& a_alloc = Alloc()) : ref(node, ids, N, creation, a_alloc) { BOOST_STATIC_ASSERT(N >= 3 && N <= 5); } - ref(const atom& node, uint32_t id0, uint32_t id1, uint32_t id2, unsigned int creation, + ref(const atom& node, uint32_t id0, uint32_t id1, uint32_t id2, uint32_t creation, const Alloc& a_alloc = Alloc()) : ref(node, {id0, id1, id2}, creation, a_alloc) {} @@ -207,7 +207,7 @@ class ref { * Get the creation number from the REF. * @return the creation number from the REF. */ - int creation() const { return m_blob ? m_blob->data()->creation : 0; } + uint32_t creation() const { return m_blob ? m_blob->data()->creation : 0; } bool operator==(const ref& t) const { return ::memcmp(m_blob->data(), t.m_blob->data(), sizeof(ref_blob)) == 0; @@ -234,7 +234,7 @@ class ref { } size_t encode_size() const - { return 1+2+(3+node().size()) + len()*4 + 4; } + { return 1+2+(3+node().size()) + len()*4 + (creation() > 0x03 ? 4 : 1); } void encode(char* buf, int& idx, size_t size) const; diff --git a/include/eixx/marshal/ref.hxx b/include/eixx/marshal/ref.hxx index 0d4339b..2780d8f 100644 --- a/include/eixx/marshal/ref.hxx +++ b/include/eixx/marshal/ref.hxx @@ -42,8 +42,11 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) int type = get8(s); switch (type) { - case ERL_NEW_REFERENCE_EXT: - case ERL_NEWER_REFERENCE_EXT: { +#ifdef ERL_NEWER_REFERENCE_EXT + case ERL_NEWER_REFERENCE_EXT: +#endif +#ifdef ERL_NEW_REFERENCE_EXT + case ERL_NEW_REFERENCE_EXT: { int count = get16be(s); // First goes the count if (count < 0 || count > COUNT) throw err_decode_exception("Error decoding ref's count", idx+1, count); @@ -55,18 +58,23 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) atom nd(s, len); s += len; - uint32_t cre = type == ERL_NEW_REFERENCE_EXT ? (get8(s) & 0x03) + uint32_t cre = type == ERL_NEW_REFERENCE_EXT ? (get8(s) & 0x03) : get32be(s); uint32_t vals[COUNT]; - for (auto p=vals, e=p+count; p != e; ++p) - *p = uint32_t(get32be(s)); + if (type == ERL_NEW_REFERENCE_EXT) + for (auto p=vals, e=p+count; p != e; ++p) + *p = get32be(s) & 0x0003ffff; /* 18 bits */ + else + for (auto p=vals, e=p+count; p != e; ++p) + *p = get32be(s); init(nd, vals, count, cre, a_alloc); idx += s-s0; break; } +#endif case ERL_REFERENCE_EXT: { int len = atom::get_len(s); if (len < 0) @@ -75,7 +83,7 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) atom nd(s, len); s += len; - uint32_t id = get32be(s); + uint32_t id = get32be(s) & 0x0003ffff; /* 18 bits */ uint32_t cre = get8(s) & 0x03; init(nd, &id, 1u, cre, a_alloc); @@ -93,23 +101,41 @@ void ref::encode(char* buf, int& idx, size_t size) const { char* s = buf + idx; char* s0 = s; - put8(s,ERL_NEWER_REFERENCE_EXT); - /* first, number of integers */ + s++; // Skip ERL_NEW_REFERENCE_EXT + + /* first, count of ids */ put16be(s, len()); - /* then the nodename */ - put8(s,ERL_ATOM_UTF8_EXT); + + /* the nodename */ +#ifdef ERL_ATOM_UTF8_EXT + put8(s, ERL_ATOM_UTF8_EXT); +#else + put8(s, ERL_ATOM_EXT); +#endif const std::string& str = node().to_string(); unsigned short n = str.size(); put16be(s, n); memmove(s, str.c_str(), n); s += n; - /* now the integers */ - if (m_blob) { - put32be(s, m_blob->data()->creation); + /* the integers */ + const uint32_t l_cre = creation(); +#ifdef ERL_NEWER_REFERENCE_EXT + if (l_cre > 0x03 /* 2 bits */) { + *s0 = ERL_NEWER_REFERENCE_EXT; + put32be(s, l_cre); for (auto* p = ids(), *e = p + len(); p != e; ++p) put32be(s, *p); + } else { +#endif + *s0 = ERL_NEW_REFERENCE_EXT; + put8(s, l_cre & 0x03 /* 2 bits */); + for (auto* p = ids(), *e = p + len(); p != e; ++p) + put32be(s, *p & 0x0003ffff /* 18 bits */); +#ifdef ERL_NEWER_REFERENCE_EXT } +#endif + idx += s-s0; BOOST_ASSERT((size_t)idx <= size); } diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 774c3fc..4c066d9 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -45,6 +45,13 @@ namespace util { namespace eid = eixx::detail; using eid::lock_guard; + inline size_t utf8_length(const std::string& str) { + size_t count = 0; + const char* s = str.c_str(); + while (*s) count += (*s++ & 0xc0) != 0x80; + return count; + } + /// Non-garbage collected hash table for atoms. It stores strings /// as atoms so that atoms can be quickly compared to with O(1) /// complexity. The instance of this table is statically maintained @@ -82,7 +89,7 @@ namespace util { /// Returns the current number of atoms stored in the atom table. size_t allocated() const { return m_atoms.size(); } - explicit basic_atom_table(int a_max_atoms = default_size()) + explicit basic_atom_table(size_t a_max_atoms = default_size()) : m_index(a_max_atoms) { m_atoms.reserve(a_max_atoms); m_atoms.push_back(""); // The 0-th element is an empty atom (""). @@ -113,7 +120,7 @@ namespace util { { if (a_name.size() == 0) return 0; - if (a_name.size() > MAXATOMLEN) + if (a_name.size() > MAXATOMLEN_UTF8 || utf8_length(a_name) > MAXATOMLEN) return -2; size_t bucket = m_index.bucket(a_name.c_str()); int n = find_value(bucket, a_name.c_str()); From 12752b657920d1d61995cf2e04a92b8ec8c501f5 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Wed, 25 Aug 2021 18:31:06 +0800 Subject: [PATCH 163/185] hotfix underflow --- .vscode/launch.json | 12 ++++++++++++ .../eixx/connect/transport_otp_connection_tcp.hxx | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 3b910af..599e879 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -24,6 +24,18 @@ ], //"preLaunchTask": "C/C++: g++ build active file", "miDebuggerPath": "/usr/bin/gdb" + }, + { + "name": "test-node", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/src/test-node", + "args": ["-n", "a@localhost", "-r", "iex-demo1@127.0.0.1", "-v", "trace"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "lldb" } ] } \ No newline at end of file diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index f3cb716..19ac486 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -233,7 +233,7 @@ void tcp_connection::handle_epmd_read_header( m_epmd_wr = m_buf_epmd + bytes_transferred; - size_t need_bytes = 8 - (bytes_transferred - 2); + int need_bytes = 8 - (bytes_transferred - 2); if (need_bytes > 0) { boost::asio::async_read(m_socket, boost::asio::buffer(m_epmd_wr, sizeof(m_buf_epmd)-bytes_transferred), @@ -440,8 +440,8 @@ void tcp_connection::handle_read_status_header( m_node_wr = m_buf_node + bytes_transferred; - size_t need_bytes = m_expect_size - (m_node_wr - m_node_rd); - // size_t need_bytes = 5 - (bytes_transferred - 2); + int need_bytes = m_expect_size - (m_node_wr - m_node_rd); + // int need_bytes = 5 - (bytes_transferred - 2); if (need_bytes > 0) { boost::asio::async_read(m_socket, boost::asio::buffer(m_node_wr, (m_buf_node+1) - m_node_wr), From 2edd21b6647d26be8711b0c8acd17082293d183b Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 25 Aug 2021 08:44:44 -0400 Subject: [PATCH 164/185] Add configurable printing of the creation flag in pid/ref/port --- include/eixx/connect/basic_otp_mailbox.hpp | 64 ++++++++++++++++--- include/eixx/connect/basic_otp_node.hpp | 4 +- .../connect/transport_otp_connection_tcp.hxx | 8 +-- include/eixx/marshal/config.hpp | 44 +++++++++++++ include/eixx/marshal/eterm.hpp | 2 + include/eixx/marshal/pid.hpp | 6 +- include/eixx/marshal/port.hpp | 6 +- include/eixx/marshal/ref.hpp | 6 +- src/CMakeLists.txt | 3 +- src/config.cpp | 36 +++++++++++ src/test_node.cpp | 20 ++++-- test/test_eterm.cpp | 9 +++ 12 files changed, 183 insertions(+), 25 deletions(-) create mode 100644 include/eixx/marshal/config.hpp create mode 100644 src/config.cpp diff --git a/include/eixx/connect/basic_otp_mailbox.hpp b/include/eixx/connect/basic_otp_mailbox.hpp index c0944dd..f58a961 100644 --- a/include/eixx/connect/basic_otp_mailbox.hpp +++ b/include/eixx/connect/basic_otp_mailbox.hpp @@ -239,7 +239,7 @@ class basic_otp_mailbox ); /// Deliver a message to this mailbox. The call is thread-safe. - void deliver(const transport_msg& a_msg) { + void deliver(const transport_msg& a_msg) { std::unique_ptr> p(new transport_msg(a_msg)); m_queue->enqueue(p.get()); p.release(); @@ -269,23 +269,23 @@ class basic_otp_mailbox * Block until response for a RPC call arrives. * @return a pointer to ErlTerm containing the response * @exception EpiConnectionException if there was an connection error - * @throws EpiBadRPC if the corresponding RPC was incorrect + * @throws EpiBadRPC if the corresponding RPC was incorrect */ //bool receive_rpc_reply(const eterm& a_reply); /** - * Send an RPC request to a remote Erlang node. + * Send an RPC request to a remote Erlang node. * @param node remote node where execute the funcion. - * @param mod the name of the Erlang module containing the - * function to be called. - * @param fun the name of the function to call. - * @param args a list of Erlang terms, to be used as arguments - * to the function. + * @param mod the name of the Erlang module containing the + * function to be called. + * @param fun the name of the function to call. + * @param args a list of Erlang terms, to be used as arguments + * to the function. * @throws EpiBadArgument if function, module or nodename are too big * @throws EpiInvalidTerm if any of the args is invalid - * @throws EpiEncodeException if encoding fails + * @throws EpiEncodeException if encoding fails * @throws EpiConnectionException if send fails - */ + */ void send_rpc(const atom& a_node, const atom& a_mod, const atom& a_fun, @@ -294,6 +294,24 @@ class basic_otp_mailbox m_node.send_rpc(self(), a_node, a_mod, a_fun, args); } + /// Send an RPC request to a remote Erlang node. + void send_rpc(const atom& a_node, + const std::string& a_mod, + const std::string& a_fun, + const list& args, + const epid* gleader = NULL) { + m_node.send_rpc(self(), a_node, atom(a_mod), atom(a_fun), args); + } + + /// Send an RPC request to a remote Erlang node. + void send_rpc(const atom& a_node, + const char* a_mod, + const char* a_fun, + const list& args, + const epid* gleader = NULL) { + m_node.send_rpc(self(), a_node, atom(a_mod), atom(a_fun), args); + } + /** * Execute an equivalent of rpc:cast(...). Doesn't return any value. * @throws err_bad_argument @@ -307,6 +325,32 @@ class basic_otp_mailbox m_node.send_rpc_cast(self(), a_node, a_mod, a_fun, args, gleader); } + /** + * Execute an equivalent of rpc:cast(...). Doesn't return any value. + * @throws err_bad_argument + * @throws err_no_process + * @throws err_connection + */ + void send_rpc_cast(const atom& a_node, const std::string& a_mod, + const std::string& a_fun, const list& args, + const epid* gleader = NULL) + { + m_node.send_rpc_cast(self(), a_node, atom(a_mod), atom(a_fun), args, gleader); + } + + /** + * Execute an equivalent of rpc:cast(...). Doesn't return any value. + * @throws err_bad_argument + * @throws err_no_process + * @throws err_connection + */ + void send_rpc_cast(const atom& a_node, const char* a_mod, + const char* a_fun, const list& args, + const epid* gleader = NULL) + { + m_node.send_rpc_cast(self(), a_node, atom(a_mod), atom(a_fun), args, gleader); + } + /// Send exit message to all linked pids and monitoring pids void break_links(const eterm& a_reason); diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index 3abacda..2f196c8 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -82,7 +82,7 @@ class basic_otp_node: public basic_otp_node_local { class rpc_server; Mutex m_lock; - uint8_t m_creation; + uint32_t m_creation; std::atomic_int m_pid_count; std::atomic_int m_port_count; std::atomic_uint_fast64_t m_refid0; @@ -212,7 +212,7 @@ class basic_otp_node: public basic_otp_node_local { ref create_ref(); /// Get creation number - uint8_t creation() const { return m_creation; } + uint32_t creation() const { return m_creation; } /** * Set up a connection to an Erlang node, using given cookie diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index 19ac486..5e3af8a 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -614,8 +614,8 @@ void tcp_connection::handle_read_challenge_body( return; } - size_t nodename_len; - uint16_t l_dist_version = m_dist_version; + int nodename_len; + uint16_t dist_version = m_dist_version; // See: https://github.com/erlang/otp/blob/OTP-24.0.5/lib/erl_interface/src/connect/ei_connect.c#L2478 if (tag == 'n') { /* OLD */ @@ -645,7 +645,7 @@ void tcp_connection::handle_read_challenge_body( m_node_rd += 4; /* ignore peer 'creation' */ nodename_len = get16be(m_node_rd); - if (nodename_len > m_node_wr - m_node_rd) { + if (int(nodename_len) > m_node_wr - m_node_rd) { std::stringstream ss; ss << "<- RECV_CHALLENGE 'N' (error) nodename too long from node '" << this->remote_nodename() << "': " << nodename_len; @@ -708,7 +708,7 @@ void tcp_connection::handle_read_challenge_body( int siz = 0; // send complement (if dist_version upgraded in-flight) - if (m_dist_version > l_dist_version) { + if (m_dist_version > dist_version) { siz += 2 + 1 + 4 + 4; put16be(w, 9); put8(w, 'c'); diff --git a/include/eixx/marshal/config.hpp b/include/eixx/marshal/config.hpp new file mode 100644 index 0000000..b0aead7 --- /dev/null +++ b/include/eixx/marshal/config.hpp @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------------- +/// \file config.hpp +//---------------------------------------------------------------------------- +/// \brief A class encapsulation static configuration options +//---------------------------------------------------------------------------- +// Copyright (c) 2021 Serge Aleynikov +// Created: 2021-08-25 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +Copyright 2010 Serge Aleynikov + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +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. + +***** END LICENSE BLOCK ***** +*/ + +#pragma once + +namespace eixx { +namespace marshal { + +/// Static configuration +class config { + static bool s_display_creation; +public: + /// When true - include 'Creation' in printing to string/stream + static bool display_creation() { return s_display_creation; } + static void display_creation(bool v) { s_display_creation = v; } +}; + +} // namespace marshal +} // namespace eixx diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 3d6e277..abd7b2a 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -50,6 +50,8 @@ limitations under the License. #include namespace eixx { + using marshal::config; + namespace marshal { namespace { diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index 31d9543..a9db24c 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -34,6 +34,7 @@ limitations under the License. #include #include #include +#include namespace eixx { namespace marshal { @@ -96,6 +97,9 @@ class epid { static const epid null; + /// When true - include 'Creation' in printing to string/stream + static bool display_creation() { return config::display_creation(); } + epid() : m_blob(nullptr) {} /** @@ -212,7 +216,7 @@ class epid { std::ostream& dump(std::ostream& out, const varbind* binding=NULL) const { out << "#Pid<" << node() << '.' << id() << '.' << serial(); - if (creation() > 0) + if (creation() > 0 && display_creation()) out << ',' << creation(); return out << '>'; } diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index 77b9f19..197fd7f 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -33,6 +33,7 @@ limitations under the License. #include #include #include +#include namespace eixx { namespace marshal { @@ -72,6 +73,9 @@ class port { public: static const port null; + /// When true - include 'Creation' in printing to string/stream + static bool display_creation() { return config::display_creation(); } + port() : m_blob(nullptr) {} /** @@ -179,7 +183,7 @@ namespace std { template ostream& operator<< (ostream& out, const eixx::marshal::port& a) { out << "#Port<" << a.node() << "." << a.id(); - if (a.creation() > 0) + if (a.creation() > 0 && a.display_creation()) out << ',' << a.creation(); return out << '>'; } diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index fb44088..bb478bf 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -34,6 +34,7 @@ limitations under the License. #include #include #include +#include #include namespace eixx { @@ -107,6 +108,9 @@ class ref { static const ref null; + /// When true - include 'Creation' in printing to string/stream + static bool display_creation() { return config::display_creation(); } + ref() : m_blob(nullptr) {} /** @@ -256,7 +260,7 @@ namespace std { out << "#Ref<" << a.node(); for (int i=0, e=a.len(); i != e; ++i) out << '.' << a.id(i); - if (a.creation() > 0) + if (a.creation() > 0 && a.display_creation()) out << ',' << a.creation(); return out << '>'; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a625b85..1129e9e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,6 +2,7 @@ list(APPEND EIXX_SRCS am.cpp + config.cpp ) if (NOT EIXX_MARSHAL_ONLY) @@ -66,4 +67,4 @@ if (NOT EIXX_MARSHAL_ONLY) test-node RUNTIME DESTINATION test ) -endif() \ No newline at end of file +endif() diff --git a/src/config.cpp b/src/config.cpp new file mode 100644 index 0000000..b41a346 --- /dev/null +++ b/src/config.cpp @@ -0,0 +1,36 @@ +//---------------------------------------------------------------------------- +/// \file config.hpp +//---------------------------------------------------------------------------- +/// \brief A class encapsulation static configuration options +//---------------------------------------------------------------------------- +// Copyright (c) 2021 Serge Aleynikov +// Created: 2021-08-25 +//---------------------------------------------------------------------------- +/* +***** BEGIN LICENSE BLOCK ***** + +Copyright 2010 Serge Aleynikov + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +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. + +***** END LICENSE BLOCK ***** +*/ + +#include + +namespace eixx { +namespace marshal { + +bool config::s_display_creation = true; + +}} // eixx::marshal diff --git a/src/test_node.cpp b/src/test_node.cpp index d8815f6..825c268 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -43,10 +43,12 @@ bool on_io_request(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) { return true; varbind l_binding; - if (s_put_chars.match(a_msg->msg(), &l_binding)) - std::cerr << "I/O request from server: " - << l_binding[S]->to_string() << std::endl; - else + if (s_put_chars.match(a_msg->msg(), &l_binding)) { + auto s = l_binding[S]->to_string(); + std::cerr << "I/O request from server: " << s << std::endl; + if (s == "<<\"DONE\">>") + a_mbox.node().stop(); + } else std::cerr << "I/O server got a message: " << a_msg->msg() << std::endl; return true; @@ -77,6 +79,10 @@ bool on_main_msg(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) { "Server time: %02d:%02d:%02d.%06ld\n", #endif tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); + + std::cout << "Sending DONE message" << std::endl; + g_io_server->send_rpc_cast(g_rem_node, "io", "put_chars", + list::make("DONE"), &g_io_server->self()); } else if (l_msg.match(s_stop)) { a_mbox.node().stop(); return false; @@ -92,9 +98,13 @@ void on_connect(otp_connection* a_con, const std::string& a_error) { return; } + if (g_rem_node != a_con->remote_nodename()) + throw eixx::err_connection("Connection from the wrong node: " + + a_con->remote_nodename().to_string()); + // Make sure that remote node has a process registered as "test". // Try sending a message to it. - g_main->send_rpc(a_con->remote_nodename(), "erlang", "now", list::make()); + g_main->send_rpc(g_rem_node, "erlang", "now", list::make()); // Send an rpc request to print a string. The remote g_io_server->send_rpc_cast(a_con->remote_nodename(), atom("io"), atom("put_chars"), diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index d5ecac1..4e352ea 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -447,6 +447,9 @@ BOOST_AUTO_TEST_CASE( test_pid ) BOOST_CHECK(t.initialized()); BOOST_CHECK_EQUAL(PID, t.type()); BOOST_CHECK_EQUAL("#Pid", t.to_string()); + config::display_creation(false); + BOOST_CHECK_EQUAL("#Pid", t.to_string()); + config::display_creation(true); BOOST_CHECK_EQUAL("#Pid", eterm(epid("abc@fc12", 1, 2, 0, alloc)).to_string()); } @@ -538,6 +541,9 @@ BOOST_AUTO_TEST_CASE( test_port ) BOOST_CHECK(t.initialized()); BOOST_CHECK_EQUAL(PORT, t.type()); BOOST_CHECK_EQUAL("#Port", t.to_string()); + config::display_creation(false); + BOOST_CHECK_EQUAL("#Port", t.to_string()); + config::display_creation(true); BOOST_CHECK_EQUAL("#Port", eterm(port("abc@fc12",1,0)).to_string()); port et1("abc@fc12", 1, 2, alloc); port et2("abc@fc12", 1, 0, alloc); @@ -580,6 +586,9 @@ BOOST_AUTO_TEST_CASE( test_ref ) BOOST_CHECK(t.initialized()); BOOST_CHECK_EQUAL(REF, t.type()); BOOST_CHECK_EQUAL("#Ref", t.to_string()); + config::display_creation(false); + BOOST_CHECK_EQUAL("#Ref", t.to_string()); + config::display_creation(true); ref et1("abc@fc12", ids, 0, alloc); BOOST_CHECK_EQUAL("#Ref", eterm(et1).to_string()); BOOST_CHECK_NE(et, et1); From b75330bcb2cf55bfc8375d7f9b530835113d9f74 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 25 Aug 2021 10:10:31 -0400 Subject: [PATCH 165/185] Partial fix for failing test cases --- include/eixx/marshal/pid.hpp | 10 +++- include/eixx/marshal/pid.hxx | 9 +-- include/eixx/marshal/port.hpp | 10 +++- include/eixx/marshal/port.hxx | 21 ++----- include/eixx/marshal/ref.hpp | 10 +++- include/eixx/marshal/ref.hxx | 38 ++++++------ test/test_eterm_encode.cpp | 105 ++++++++++++++++++---------------- 7 files changed, 107 insertions(+), 96 deletions(-) diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index a9db24c..b68a2f9 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -209,7 +209,15 @@ class epid { if (creation() < t2.creation()) return true; return false; } - size_t encode_size() const { return (creation() > 0x03 ? 16 : 13) + node().size(); } + size_t encode_size() const { + return + #ifndef ERL_NEW_PID_EXT + 13 + #elif defined(ERL_PID_EXT) + 16 + #endif + + node().size(); + } void encode(char* buf, int& idx, size_t size) const; diff --git a/include/eixx/marshal/pid.hxx b/include/eixx/marshal/pid.hxx index 1a786a1..044caf2 100644 --- a/include/eixx/marshal/pid.hxx +++ b/include/eixx/marshal/pid.hxx @@ -91,13 +91,8 @@ void epid::encode(char* buf, int& idx, size_t size) const put32be(s, serial()); /* 13 bits if distribution flag DFLAG_V4_NC is not set */ const uint32_t l_cre = creation(); #ifdef ERL_NEW_PID_EXT - if (l_cre > 0x03 /* 2 bits */) { - *s0 = ERL_NEW_PID_EXT; - put32be(s, l_cre); - } else { - *s0 = ERL_PID_EXT; - put8(s, l_cre & 0x03 /* 2 bits */); - } + *s0 = ERL_NEW_PID_EXT; + put32be(s, l_cre); #else *s0 = ERL_PID_EXT; put8(s, l_cre & 0x03 /* 2 bits */); diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index 197fd7f..e72d743 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -167,7 +167,15 @@ class port { return false; } - size_t encode_size() const { return (id() > 0x0fffffff ? 16 : creation() > 0x03 ? 12 : 9) + node().size(); } + size_t encode_size() const { + return id() > 0x0fffffff ? 16 : + #if defined(ERL_V4_PORT_EXT) || defined(ERL_NEW_PORT_EXT) + 12 + #else + 9 + #endif + + node().size(); + } void encode(char* buf, int& idx, size_t size) const; diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index 3eb76df..ec56d68 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -67,7 +67,7 @@ port::port(const char *buf, int& idx, size_t size, const Alloc& a_alloc) #endif #ifdef ERL_NEW_PORT_EXT case ERL_NEW_PORT_EXT: - id = uint64_t(get32be(s) & 0x0fffffff); /* 28 bits */ + id = uint64_t(get32be(s)); cre = get32be(s); break; #endif @@ -108,26 +108,17 @@ void port::encode(char* buf, int& idx, size_t size) const *s0 = ERL_V4_PORT_EXT; put64be(s, id()); put32be(s, l_cre); - - #ifdef ERL_NEW_PORT_EXT - } else if (l_cre > 0x03 /* 2 bits */) { - *s0 = ERL_NEW_PORT_EXT; - put32be(s, id() & 0x0fffffff /* 28 bits */); - put32be(s, l_cre); - #else } else { - #endif #elif defined(ERL_NEW_PORT_EXT) - if (l_cre > 0x03 /* 2 bits */) { *s0 = ERL_NEW_PORT_EXT; - put32be(s, id() & 0x0fffffff /* 28 bits */); + put32be(s, id()); put32be(s, l_cre); - } else { -#endif +#else *s0 = ERL_PORT_EXT; put32be(s, id() & 0x0fffffff /* 28 bits */); - put8(s, l_cre); -#if defined(ERL_V4_PORT_EXT) || defined(ERL_NEW_PORT_EXT) + put8(s, l_cre & 0x03 /* 2 bits */); +#endif +#if defined(ERL_V4_PORT_EXT) } #endif diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index bb478bf..852cbc6 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -237,8 +237,14 @@ class ref { return false; } - size_t encode_size() const - { return 1+2+(3+node().size()) + len()*4 + (creation() > 0x03 ? 4 : 1); } + size_t encode_size() const { + return 1+2+(3+node().size()) + len()*4 + + #ifdef ERL_NEWER_REFERENCE_EXT + 4; + #else + 1; + #endif + } void encode(char* buf, int& idx, size_t size) const; diff --git a/include/eixx/marshal/ref.hxx b/include/eixx/marshal/ref.hxx index 2780d8f..d8d4603 100644 --- a/include/eixx/marshal/ref.hxx +++ b/include/eixx/marshal/ref.hxx @@ -58,16 +58,14 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) atom nd(s, len); s += len; - uint32_t cre = type == ERL_NEW_REFERENCE_EXT ? (get8(s) & 0x03) - : get32be(s); + uint32_t cre, mask; + std::tie(cre, mask) = type == ERL_NEW_REFERENCE_EXT + ? std::make_pair((get8(s) & 0x03u), 0x0003ffffu) /* 18 bits */ + : std::make_pair(uint32_t(get32be(s)), 0xFFFFffff); uint32_t vals[COUNT]; - if (type == ERL_NEW_REFERENCE_EXT) - for (auto p=vals, e=p+count; p != e; ++p) - *p = get32be(s) & 0x0003ffff; /* 18 bits */ - else - for (auto p=vals, e=p+count; p != e; ++p) - *p = get32be(s); + for (auto p=vals, e=p+count; p != e; ++p) + *p = get32be(s) & mask; init(nd, vals, count, cre, a_alloc); @@ -84,7 +82,7 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) s += len; uint32_t id = get32be(s) & 0x0003ffff; /* 18 bits */ - uint32_t cre = get8(s) & 0x03; + uint32_t cre = get8(s) & 0x03; init(nd, &id, 1u, cre, a_alloc); @@ -121,19 +119,15 @@ void ref::encode(char* buf, int& idx, size_t size) const /* the integers */ const uint32_t l_cre = creation(); #ifdef ERL_NEWER_REFERENCE_EXT - if (l_cre > 0x03 /* 2 bits */) { - *s0 = ERL_NEWER_REFERENCE_EXT; - put32be(s, l_cre); - for (auto* p = ids(), *e = p + len(); p != e; ++p) - put32be(s, *p); - } else { -#endif - *s0 = ERL_NEW_REFERENCE_EXT; - put8(s, l_cre & 0x03 /* 2 bits */); - for (auto* p = ids(), *e = p + len(); p != e; ++p) - put32be(s, *p & 0x0003ffff /* 18 bits */); -#ifdef ERL_NEWER_REFERENCE_EXT - } + *s0 = ERL_NEWER_REFERENCE_EXT; + put32be(s, l_cre); + for (auto* p = ids(), *e = p + len(); p != e; ++p) + put32be(s, *p); +#else + *s0 = ERL_NEW_REFERENCE_EXT; + put8(s, l_cre & 0x03 /* 2 bits */); + for (auto* p = ids(), *e = p + len(); p != e; ++p) + put32be(s, *p & 0x0003ffff /* 18 bits */); #endif idx += s-s0; diff --git a/test/test_eterm_encode.cpp b/test/test_eterm_encode.cpp index 50712e7..2d6e07a 100644 --- a/test/test_eterm_encode.cpp +++ b/test/test_eterm_encode.cpp @@ -30,28 +30,37 @@ BOOST_AUTO_TEST_CASE( test_encode_string ) eterm t("abc"); string s(t.encode(0)); const uint8_t expect[] = {131,107,0,3,97,98,99}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte string t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(3ul, t1.size()); + BOOST_CHECK_EQUAL(3ul, t1.size()); eterm et(t1); std::string str( et.to_string() ); if (!(et == t)) - BOOST_REQUIRE_EQUAL(et, t); + BOOST_CHECK_EQUAL(et, t); if (str != "\"abc\"") - BOOST_REQUIRE_EQUAL("\"abc\"", str); + BOOST_CHECK_EQUAL("\"abc\"", str); } BOOST_AUTO_TEST_CASE( test_encode_atom ) { eterm a(atom("abc")); string s(a.encode(0)); - const uint8_t expect[] = {131,ERL_ATOM_UTF8_EXT,0,3,97,98,99}; - BOOST_REQUIRE(s.equal(expect)); + const uint8_t expect[] = {131,119,0,3,97,98,99}; + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte atom t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(3ul, t1.size()); - BOOST_REQUIRE_EQUAL("abc", eterm(t1).to_string()); + BOOST_CHECK_EQUAL(3ul, t1.size()); + BOOST_CHECK_EQUAL("abc", eterm(t1).to_string()); + + const uint8_t expect2[] = {131,119,2,209,132}; + eterm a2(atom("abc")); + string s2(a2.encode(0)); + BOOST_CHECK(s2.equal(expect2)); + idx = 1; // skipping the magic byte + atom t2((const char*)expect2, idx, sizeof(expect2)); + BOOST_CHECK_EQUAL(2ul, t2.size()); + BOOST_CHECK_EQUAL("Ñ„", eterm(t2).to_string()); } BOOST_AUTO_TEST_CASE( test_encode_binary ) @@ -60,7 +69,7 @@ BOOST_AUTO_TEST_CASE( test_encode_binary ) eterm t(binary(data, sizeof(data))); string s(t.encode(0)); const uint8_t expect[] = {131,109,0,0,0,13,1,2,3,4,5,6,7,8,9,10,11,12,13}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); } BOOST_AUTO_TEST_CASE( test_encode_double ) @@ -69,24 +78,24 @@ BOOST_AUTO_TEST_CASE( test_encode_double ) eterm t(d); string s(t.encode(0)); const uint8_t expect[] = {131,70,64,200,28,214,230,49,248,161}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(d, t1.to_double()); + BOOST_CHECK_EQUAL(d, t1.to_double()); } BOOST_AUTO_TEST_CASE( test_encode_emptylist ) { list l(0); - BOOST_REQUIRE(l.initialized()); + BOOST_CHECK(l.initialized()); eterm t(l); string s(t.encode(0)); const uint8_t expect[] = {131,106}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(LIST, t1.type()); - BOOST_REQUIRE_EQUAL(0ul, t1.to_list().length()); + BOOST_CHECK_EQUAL(LIST, t1.type()); + BOOST_CHECK_EQUAL(0ul, t1.to_list().length()); } BOOST_AUTO_TEST_CASE( test_encode_list ) @@ -102,12 +111,12 @@ BOOST_AUTO_TEST_CASE( test_encode_list ) string s(t.encode(0)); const uint8_t expect[] = {131,108,0,0,0,4,ERL_ATOM_UTF8_EXT,0,3,97,98,99, 107,0,2,101,102,97,1,107,0,2,103,104,106}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte list t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(4ul, t1.length()); + BOOST_CHECK_EQUAL(4ul, t1.length()); std::string str(eterm(t1).to_string()); - BOOST_REQUIRE_EQUAL("[abc,\"ef\",1,\"gh\"]", str); + BOOST_CHECK_EQUAL("[abc,\"ef\",1,\"gh\"]", str); } BOOST_AUTO_TEST_CASE( test_encode_long ) @@ -117,20 +126,20 @@ BOOST_AUTO_TEST_CASE( test_encode_long ) eterm t(d); string s(t.encode(0)); const uint8_t expect[] = {131,97,123}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(d, t1.to_long()); + BOOST_CHECK_EQUAL(d, t1.to_long()); } { long d = 12345; eterm t(d); string s(t.encode(0)); const uint8_t expect[] = {131,98,0,0,48,57}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(d, t1.to_long()); + BOOST_CHECK_EQUAL(d, t1.to_long()); } { #if EIXX_SIZEOF_LONG >= 8 @@ -145,10 +154,10 @@ BOOST_AUTO_TEST_CASE( test_encode_long ) #else const uint8_t expect[] = {131,110,4,0,0x78,0x56,0x34,0x12}; #endif // EIXX_SIZEOF_LONG >= 8 - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(d, t1.to_long()); + BOOST_CHECK_EQUAL(d, t1.to_long()); } } @@ -156,15 +165,15 @@ BOOST_AUTO_TEST_CASE( test_encode_pid ) { { eterm t(epid("test@host", 1, 2, 0)); - BOOST_REQUIRE_EQUAL("#Pid", t.to_string()); + BOOST_CHECK_EQUAL("#Pid", t.to_string()); string s(t.encode(0)); //std::cout << s.to_binary_string() << std::endl; const uint8_t expect[] = {131,88,118,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0,0,0,2,0,0,0,0}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte eterm pid(epid((const char*)expect, idx, sizeof(expect))); - BOOST_REQUIRE_EQUAL(eterm(pid), t); + BOOST_CHECK_EQUAL(eterm(pid), t); } { const uint8_t expect[] = @@ -172,37 +181,37 @@ BOOST_AUTO_TEST_CASE( test_encode_pid ) int idx = 1; // skipping the magic byte epid decode_pid((const char*)expect, idx, sizeof(expect)); epid expect_pid("test@host", 1, 2, 3); - BOOST_REQUIRE_EQUAL(expect_pid, decode_pid); + BOOST_CHECK_EQUAL(expect_pid, decode_pid); } } BOOST_AUTO_TEST_CASE( test_encode_port ) { eterm t(port("test@host", 1, 0)); - BOOST_REQUIRE_EQUAL("#Port", t.to_string()); + BOOST_CHECK_EQUAL("#Port", t.to_string()); string s(t.encode(0)); //std::cout << s.to_binary_string() << std::endl; const uint8_t expect[] = {131,102,ERL_ATOM_UTF8_EXT,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(t1, t); + BOOST_CHECK_EQUAL(t1, t); } BOOST_AUTO_TEST_CASE( test_encode_ref ) { uint32_t ids[] = {1,2,3}; eterm t(ref("test@host", ids, 0)); - BOOST_REQUIRE_EQUAL("#Ref", t.to_string()); + BOOST_CHECK_EQUAL("#Ref", t.to_string()); string s(t.encode(0)); //std::cout << s.to_binary_string() << std::endl; const uint8_t expect[] = {131,90,0,3,100,0,9,116,101,115,116,64,104,111,115,116,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte ref t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(eterm(t1), t); + BOOST_CHECK_EQUAL(eterm(t1), t); { ref t(atom("abc@fc12"), 993, 0, 0, 2); //std::cout << string(eterm(t).encode(0)).to_binary_string() << std::endl; @@ -210,7 +219,7 @@ BOOST_AUTO_TEST_CASE( test_encode_ref ) {131,90,0,3,118,0,8,97,98,99,64,102,99,49,50,0,0,0,2,0,0,3,225,0,0,0,0,0,0,0,0}; int idx = 1; // skipping the magic byte ref t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(t1, t); + BOOST_CHECK_EQUAL(t1, t); } } @@ -236,11 +245,11 @@ BOOST_AUTO_TEST_CASE( test_encode_tuple ) const uint8_t expect[] = {131,104,5,ERL_ATOM_UTF8_EXT,0,3,97,98,99,107,0,2,101,102,97,1, 104,4,ERL_ATOM_UTF8_EXT,0,1,97,107,0,2,120,120,70,64,94,198,102, 102,102,102,102,97,5,107,0,2,103,104}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte tuple t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(5ul, t1.size()); - BOOST_REQUIRE_EQUAL("{abc,\"ef\",1,{a,\"xx\",123.1,5},\"gh\"}", eterm(t1).to_string()); + BOOST_CHECK_EQUAL(5ul, t1.size()); + BOOST_CHECK_EQUAL("{abc,\"ef\",1,{a,\"xx\",123.1,5},\"gh\"}", eterm(t1).to_string()); } BOOST_AUTO_TEST_CASE( test_encode_trace ) @@ -252,16 +261,16 @@ BOOST_AUTO_TEST_CASE( test_encode_trace ) //std::cout << to_binary_string(s) << std::endl; const uint8_t expect[] = {131,104,5,97,1,97,2,97,3,88,118,0,8,97,98,99,64,102,99,49,50,0,0,0,96,0,0,0,0,0,0,0,3,97,4}; - BOOST_REQUIRE(s.equal(expect)); + BOOST_CHECK(s.equal(expect)); int idx = 1; // skipping the magic byte trace t1((const char*)expect, idx, sizeof(expect)); - BOOST_REQUIRE_EQUAL(5ul, t1.size()); - BOOST_REQUIRE_EQUAL(1, t1.flags()); - BOOST_REQUIRE_EQUAL(2, t1.label()); - BOOST_REQUIRE_EQUAL(3, t1.serial()); - BOOST_REQUIRE(self == t1.from()); - BOOST_REQUIRE_EQUAL(4, t1.prev()); - BOOST_REQUIRE_EQUAL("{1,2,3,#Pid,4}", eterm(t1).to_string()); + BOOST_CHECK_EQUAL(5ul, t1.size()); + BOOST_CHECK_EQUAL(1, t1.flags()); + BOOST_CHECK_EQUAL(2, t1.label()); + BOOST_CHECK_EQUAL(3, t1.serial()); + BOOST_CHECK(self == t1.from()); + BOOST_CHECK_EQUAL(4, t1.prev()); + BOOST_CHECK_EQUAL("{1,2,3,#Pid,4}", eterm(t1).to_string()); } BOOST_AUTO_TEST_CASE( test_encode_rpc ) @@ -287,12 +296,12 @@ BOOST_AUTO_TEST_CASE( test_encode_rpc ) // ['ECG','ECG.H1.001',#Pid<'ECG.H1.001@f16'.1.0.0>,"example_core",2000],user}} char l_buf[256]; size_t l_sz = l_term.encode_size(0, true); - BOOST_REQUIRE(l_sz < sizeof(l_buf)); + BOOST_CHECK(l_sz < sizeof(l_buf)); l_term.encode(l_buf, l_sz, 0, true); std::string s = std::string(l_buf, l_sz); std::string s_exp = std::string(l_buf, sizeof(s_expected)); if (s != s_exp) std::cout << "String: " << to_binary_string(s.c_str(), s.size()) << std::endl; - BOOST_REQUIRE_EQUAL(s_exp, s); + BOOST_CHECK_EQUAL(s_exp, s); } From 5c0baa3b820b07fca3a5880d972445aee38b46c1 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 25 Aug 2021 10:16:39 -0400 Subject: [PATCH 166/185] Fix test --- src/test_node.cpp | 87 ++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/src/test_node.cpp b/src/test_node.cpp index 825c268..90fec26 100644 --- a/src/test_node.cpp +++ b/src/test_node.cpp @@ -35,26 +35,40 @@ static const atom N1 = atom("N1"); static const atom N2 = atom("N2"); static const atom N3 = atom("N3"); -bool on_io_request(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) { +void on_connect(otp_connection* a_con, const std::string& a_error) { + if (!a_error.empty()) { + std::cout << a_error << std::endl; + return; + } - static const eterm s_put_chars = eterm::format("{io_request,_,_,{put_chars,S}}"); + if (g_rem_node != a_con->remote_nodename()) + throw eixx::err_connection("Connection from the wrong node: " + + a_con->remote_nodename().to_string()); - if (!a_msg) - return true; + // Make sure that remote node has a process registered as "test". + // Try sending a message to it. + g_main->send_rpc(a_con->remote_nodename(), "erlang", "now", list::make()); - varbind l_binding; - if (s_put_chars.match(a_msg->msg(), &l_binding)) { - auto s = l_binding[S]->to_string(); - std::cerr << "I/O request from server: " << s << std::endl; - if (s == "<<\"DONE\">>") - a_mbox.node().stop(); - } else - std::cerr << "I/O server got a message: " << a_msg->msg() << std::endl; + // Send an rpc request to print a string. The remote + g_io_server->send_rpc_cast(a_con->remote_nodename(), atom("io"), atom("put_chars"), + list::make("This is a test string"), &g_io_server->self()); - return true; + g_io_server->send_rpc_cast(a_con->remote_nodename(), atom("io"), atom("put_chars"), + list::make("DONE"), &g_io_server->self()); } -bool on_main_msg(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) { +void on_disconnect( + otp_node& a_node, const otp_connection& a_con, + atom a_remote_node, const boost::system::error_code& err) +{ + std::cout << "Disconnected from remote node " << a_remote_node << std::endl; + if (a_con.reconnect_timeout() == 0) + a_node.stop(); +} + +// Messages to the 'main' mailbox +bool on_msg(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) +{ static const eterm s_now_pattern = eterm::format("{rex, {N1, N2, N3}}"); static const eterm s_stop = atom("stop"); @@ -92,32 +106,25 @@ bool on_main_msg(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) { return true; } -void on_connect(otp_connection* a_con, const std::string& a_error) { - if (!a_error.empty()) { - std::cout << a_error << std::endl; - return; - } - - if (g_rem_node != a_con->remote_nodename()) - throw eixx::err_connection("Connection from the wrong node: " + - a_con->remote_nodename().to_string()); +bool on_io(otp_mailbox& a_mbox, eixx::transport_msg*& a_msg) +{ + static const eterm s_put_chars = eterm::format("{io_request,_,_,{put_chars,S}}"); - // Make sure that remote node has a process registered as "test". - // Try sending a message to it. - g_main->send_rpc(g_rem_node, "erlang", "now", list::make()); + if (!a_msg) + return true; - // Send an rpc request to print a string. The remote - g_io_server->send_rpc_cast(a_con->remote_nodename(), atom("io"), atom("put_chars"), - list::make("This is a test string"), &g_io_server->self()); -} + varbind l_binding; + if (s_put_chars.match(a_msg->msg(), &l_binding)) { + std::cerr << "I/O request from server: " + << l_binding[S]->to_string() << std::endl; + auto s = l_binding[S]->to_string(); + if (s == "<<\"DONE\">>") + a_mbox.node().stop(); + } + else + std::cerr << "I/O server got a message: " << a_msg->msg() << std::endl; -void on_disconnect( - otp_node& a_node, const otp_connection& a_con, - atom a_remote_node, const boost::system::error_code& err) -{ - std::cout << "Disconnected from remote node " << a_remote_node << std::endl; - if (a_con.reconnect_timeout() == 0) - a_node.stop(); + return true; } int main(int argc, char* argv[]) { @@ -159,11 +166,13 @@ int main(int argc, char* argv[]) { node.connect(on_connect, g_rem_node, reconnect_secs); //otp_connection::connection_type* transport = a_con->transport(); - g_io_server->async_receive(on_io_request, std::chrono::milliseconds(-1), -1); + g_io_server->async_receive(on_io, + // IO Request + std::chrono::milliseconds(-1), -1); //node.send_rpc(self, g_rem_node, atom("shell_default"), atom("ls"), // list::make(), &g_io_server); - g_main->async_receive(on_main_msg, std::chrono::seconds(5), -1); + g_main->async_receive(on_msg, std::chrono::seconds(5), -1); node.run(); From 20c300b3cf20ad97a7f477e52ff9eb8e1fa5b810 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Tue, 24 Aug 2021 23:28:40 +0800 Subject: [PATCH 167/185] fix conversion warnings --- CMakeLists.txt | 4 +- include/eixx/connect/basic_otp_connection.hpp | 4 +- include/eixx/connect/basic_otp_node.hpp | 4 +- include/eixx/connect/basic_otp_node.hxx | 4 +- .../eixx/connect/transport_otp_connection.hpp | 2 +- .../eixx/connect/transport_otp_connection.hxx | 29 +++++---- .../connect/transport_otp_connection_tcp.hpp | 1 + .../connect/transport_otp_connection_tcp.hxx | 59 +++++++++++-------- include/eixx/eterm_exception.hpp | 27 ++++++--- include/eixx/marshal/atom.hpp | 26 ++++---- include/eixx/marshal/binary.hpp | 8 +-- include/eixx/marshal/binary.hxx | 17 +++--- include/eixx/marshal/eterm.hpp | 4 +- include/eixx/marshal/eterm.hxx | 25 ++++---- include/eixx/marshal/eterm_format.hxx | 10 ++-- include/eixx/marshal/list.hpp | 4 +- include/eixx/marshal/list.hxx | 18 ++++-- include/eixx/marshal/map.hpp | 13 ++-- include/eixx/marshal/pid.hpp | 8 +-- include/eixx/marshal/pid.hxx | 8 +-- include/eixx/marshal/port.hpp | 6 +- include/eixx/marshal/port.hxx | 12 ++-- include/eixx/marshal/ref.hpp | 16 ++--- include/eixx/marshal/ref.hxx | 14 ++--- include/eixx/marshal/string.hpp | 14 +++-- include/eixx/marshal/trace.hpp | 10 ++-- include/eixx/marshal/tuple.hpp | 12 ++-- include/eixx/marshal/tuple.hxx | 13 ++-- include/eixx/marshal/var.hpp | 2 +- include/eixx/marshal/visit_encode_size.hpp | 2 +- include/eixx/marshal/visit_encoder.hpp | 19 ++++-- include/eixx/marshal/visit_subst.hpp | 2 +- include/eixx/util/async_queue.hpp | 2 +- include/eixx/util/atom_table.hpp | 7 ++- include/eixx/util/hashtable.hpp | 5 +- 35 files changed, 238 insertions(+), 173 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a09c87..3a6283f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ if("${toolchain}" STREQUAL "gcc") if(NOT CMAKE_CXX_COMPILER) set(CMAKE_CXX_COMPILER "g++") endif() - add_definitions(-fopenmp -Wall -Wno-strict-aliasing) + add_definitions(-fopenmp -Wall -Wextra -Wpedantic -Wno-strict-aliasing -Wconversion) if("${CMAKE_BUILD_TYPE}" STREQUAL "release") add_definitions(-flto -funroll-loops -fomit-frame-pointer) @@ -53,7 +53,7 @@ elseif("${toolchain}" STREQUAL "intel") elseif("${toolchain}" STREQUAL "clang") set(CMAKE_C_COMPILER "clang") set(CMAKE_CXX_COMPILER "clang++") - add_definitions(-Wall -Wno-strict-aliasing) + add_definitions(-Wall -Wextra -Wpedantic -Wno-strict-aliasing -Wconversion) else() message(FATAL_ERROR "Invalid toolchain: ${TOOLCHAIN}") endif() diff --git a/include/eixx/connect/basic_otp_connection.hpp b/include/eixx/connect/basic_otp_connection.hpp index 99cfedf..334f0fb 100644 --- a/include/eixx/connect/basic_otp_connection.hpp +++ b/include/eixx/connect/basic_otp_connection.hpp @@ -127,7 +127,7 @@ class basic_otp_connection int reconnect_timeout() const { return m_reconnect_secs; } /// Set new reconnect timeout in seconds - void reconnect_timeout(size_t a_reconnect_secs) { m_reconnect_secs = a_reconnect_secs; } + void reconnect_timeout(int a_reconnect_secs) { m_reconnect_secs = a_reconnect_secs; } static pointer connect(connect_completion_handler h, @@ -218,7 +218,7 @@ class basic_otp_connection report_status(REPORT_ERROR, str.str()); } - void on_message(connection_type* a_con, const transport_msg& a_tm) { + void on_message(connection_type*, const transport_msg& a_tm) { try { m_node->deliver(a_tm); } catch (std::exception& e) { diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index 3abacda..1c2db99 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -226,7 +226,7 @@ class basic_otp_node: public basic_otp_node_local { */ template void connect(CompletionHandler h, const atom& a_remote_node, - const atom& a_cookie = atom(), size_t a_reconnect_secs = 0); + const atom& a_cookie = atom(), int a_reconnect_secs = 0); /** * Set up a connection to an Erlang node, using default cookie @@ -239,7 +239,7 @@ class basic_otp_node: public basic_otp_node_local { */ template void connect(CompletionHandler h, const atom& a_remote_nodename, - size_t a_reconnect_secs = 0); + int a_reconnect_secs = 0); /// Get connection identified by the \a a_node name. /// @throws err_connection if not connected to \a a_node._ diff --git a/include/eixx/connect/basic_otp_node.hxx b/include/eixx/connect/basic_otp_node.hxx index 754fccd..f25abc2 100644 --- a/include/eixx/connect/basic_otp_node.hxx +++ b/include/eixx/connect/basic_otp_node.hxx @@ -188,7 +188,7 @@ close() template template inline void basic_otp_node:: -connect(CompletionHandler h, const atom& a_remote_nodename, size_t a_reconnect_secs) +connect(CompletionHandler h, const atom& a_remote_nodename, int a_reconnect_secs) { connect(h, a_remote_nodename, atom(), a_reconnect_secs); } @@ -208,7 +208,7 @@ template template void basic_otp_node:: connect(CompletionHandler h, const atom& a_remote_node, const atom& a_cookie, - size_t a_reconnect_secs) + int a_reconnect_secs) { lock_guard guard(m_lock); typename conn_hash_map::iterator it = m_connections.find(a_remote_node); diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index 2016226..dc93492 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -261,7 +261,7 @@ class connection /// and \a a_msg are invalid. /// @return Control Message /// @throws err_decode_exception - int transport_msg_decode(const char *mbuf, int len, transport_msg& a_tm); + int transport_msg_decode(const char *mbuf, size_t len, transport_msg& a_tm); void process_message(const char* a_buf, size_t a_size); diff --git a/include/eixx/connect/transport_otp_connection.hxx b/include/eixx/connect/transport_otp_connection.hxx index 19def05..9df07bc 100644 --- a/include/eixx/connect/transport_otp_connection.hxx +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -351,11 +351,11 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) /// @throws err_decode_exception template int connection:: -transport_msg_decode(const char *mbuf, int len, transport_msg& a_tm) +transport_msg_decode(const char *mbuf, size_t len, transport_msg& a_tm) { const char* s = mbuf; int version; - int index = 0; + uintptr_t index = 0; if (unlikely(len == 0)) // This is TICK message return ERL_TICK; @@ -363,18 +363,20 @@ transport_msg_decode(const char *mbuf, int len, transport_msg& a_tm) /* now decode header */ /* pass-through, version, control tuple header, control message type */ if (unlikely(get8(s) != ERL_PASS_THROUGH)) { - int n = len < 65 ? len : 64; - std::string s = std::string("Missing pass-throgh flag in message") + size_t n = len < 65 ? len : 64; + std::string s = std::string("Missing pass-through flag in message") + to_binary_string(mbuf, n); throw err_decode_exception(s, len); } - if (unlikely(ei_decode_version(s,&index,&version) || version != ERL_VERSION_MAGIC)) + if (unlikely(ei_decode_version(s, (int*)&index, &version) || version != ERL_VERSION_MAGIC)) throw err_decode_exception("Invalid control message magic number", version); tuple cntrl(s, index, len, m_allocator); - int msgtype = cntrl[0].to_long(); + long t = cntrl[0].to_long(); + BOOST_ASSERT(t <= INT_MAX); + int msgtype = (int)t; if (unlikely(msgtype <= ERL_TICK) || unlikely(msgtype > ERL_MONITOR_P_EXIT)) throw err_decode_exception("Invalid message type", msgtype); @@ -384,7 +386,8 @@ transport_msg_decode(const char *mbuf, int len, transport_msg& a_tm) | 1 << ERL_SEND_TT | 1 << ERL_REG_SEND_TT; if (likely((1 << msgtype) & types_with_payload)) { - if (unlikely(ei_decode_version(s,&index,&version)) || unlikely((version != ERL_VERSION_MAGIC))) + BOOST_ASSERT(index <= INT_MAX); + if (unlikely(ei_decode_version(s, (int*)&index, &version)) || unlikely((version != ERL_VERSION_MAGIC))) throw err_decode_exception("Invalid message magic number", version); eterm msg(s, index, len, m_allocator); @@ -455,10 +458,12 @@ send(const transport_msg& a_msg) bool l_has_msg= a_msg.has_msg(); size_t cntrl_sz = l_cntrl.encode_size(0, true); size_t msg_sz = l_has_msg ? a_msg.msg().encode_size(0, true) : 0; - size_t len = cntrl_sz + msg_sz + 1 /*passthrough*/ + 4 /*len*/; - char* data = allocate(len); + size_t sz = cntrl_sz + msg_sz + 1 /*passthrough*/ + 4 /*len*/; + char* data = allocate(sz); char* s = data; - put32be(s, len-4); + BOOST_ASSERT(sz-4 <= UINT32_MAX); + uint32_t len = (uint32_t)sz - 4; + put32be(s, len); *s++ = ERL_PASS_THROUGH; l_cntrl.encode(s, cntrl_sz, 0, true); if (l_has_msg) @@ -472,9 +477,9 @@ send(const transport_msg& a_msg) m_handler->report_status(REPORT_INFO, s.str()); } //if (unlikely(verbose() >= VERBOSE_WIRE)) - // std::cout << "SEND " << len << " bytes " << to_binary_string(data, len) << std::endl; + // std::cout << "SEND " << sz << " bytes " << to_binary_string(data, sz) << std::endl; - boost::asio::const_buffer b(data, len); + boost::asio::const_buffer b(data, sz); m_io_service.post( std::bind(&connection::do_write, this->shared_from_this(), b)); } diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index c618fb1..488888e 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -48,6 +48,7 @@ class tcp_connection { public: typedef connection base_t; + typedef boost::asio::ip::port_type port_t; tcp_connection(boost::asio::io_service& a_svc, Handler* a_h, const Alloc& a_alloc) : connection(TCP, a_svc, a_h, a_alloc) diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index 19ac486..b668a87 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -120,10 +120,12 @@ void tcp_connection::handle_epmd_connect( // The connection was successful. Send the request. std::string alivename = remote_alivename(); char* w = m_buf_epmd; - int len = alivename.size() + 1; - put16be(w,len); + size_t sz = alivename.size(); + BOOST_ASSERT(sz < UINT16_MAX); + uint16_t len = (uint16_t)sz + 1; + put16be(w, len); put8(w,EI_EPMD_PORT2_REQ); - strcpy(w, alivename.c_str()); + strncpy(w, alivename.c_str(), sz); if (this->handler()->verbose() >= VERBOSE_TRACE) { std::stringstream ss; @@ -200,8 +202,10 @@ void tcp_connection::handle_epmd_read_header( return; } - const char* s = m_buf_epmd; - int res = get8(s); + const char* l_epmd_rd = m_buf_epmd; + m_expect_size = 8; + + int res = get8(l_epmd_rd); if (res != EI_EPMD_PORT2_RESP) { // response type std::stringstream ss; @@ -213,7 +217,7 @@ void tcp_connection::handle_epmd_read_header( return; } - int n = get8(s); + int n = get8(l_epmd_rd); if (this->handler()->verbose() >= VERBOSE_TRACE) { std::stringstream ss; @@ -233,7 +237,8 @@ void tcp_connection::handle_epmd_read_header( m_epmd_wr = m_buf_epmd + bytes_transferred; - int need_bytes = 8 - (bytes_transferred - 2); + size_t got_bytes = bytes_transferred - 2; + size_t need_bytes = m_expect_size > got_bytes ? m_expect_size - got_bytes : 0; if (need_bytes > 0) { boost::asio::async_read(m_socket, boost::asio::buffer(m_epmd_wr, sizeof(m_buf_epmd)-bytes_transferred), @@ -263,17 +268,17 @@ void tcp_connection::handle_epmd_read_body( m_epmd_wr += bytes_transferred; #ifndef NDEBUG - int got_bytes = m_epmd_wr - m_buf_epmd; + size_t got_bytes = m_epmd_wr - m_buf_epmd; #endif BOOST_ASSERT(got_bytes >= 10); - const char* s = m_buf_epmd + 2; - int port = get16be(s); - int ntype = get8(s); - int proto = get8(s); - uint16_t dist_high = get16be(s); - uint16_t dist_low = get16be(s); - m_dist_version = (dist_high > EI_DIST_HIGH ? EI_DIST_HIGH : dist_high); + const char* l_epmd_rd = m_buf_epmd + 2; + port_t port = get16be(l_epmd_rd); + int ntype = get8(l_epmd_rd); + int proto = get8(l_epmd_rd); + uint16_t dist_high = get16be(l_epmd_rd); + uint16_t dist_low = get16be(l_epmd_rd); + m_dist_version = (dist_high > EI_DIST_HIGH ? EI_DIST_HIGH : dist_high); if (this->handler()->verbose() >= VERBOSE_TRACE) { std::stringstream ss; @@ -340,7 +345,7 @@ void tcp_connection::handle_connect(const boost::system::error_c } #endif - size_t siz; + uint16_t siz; if (tag == 'n') siz = 2 + 1 + 2 + 4 + this->local_nodename().size(); else /* tag == 'N' */ @@ -367,7 +372,7 @@ void tcp_connection::handle_connect(const boost::system::error_c m_dist_version = EI_DIST_LOW; put16be(w, EI_DIST_LOW); /* spec demands ver==5 */ #endif - put32be(w, flags); + put32be(w, flags & 0xffffffff /* FlagsLow */); } else { /* tag == 'N' */ put64be(w, flags); put32be(w, this->local_creation()); @@ -440,8 +445,8 @@ void tcp_connection::handle_read_status_header( m_node_wr = m_buf_node + bytes_transferred; - int need_bytes = m_expect_size - (m_node_wr - m_node_rd); - // int need_bytes = 5 - (bytes_transferred - 2); + size_t got_bytes = m_node_wr - m_node_rd; + size_t need_bytes = m_expect_size > got_bytes ? m_expect_size - got_bytes : 0; if (need_bytes > 0) { boost::asio::async_read(m_socket, boost::asio::buffer(m_node_wr, (m_buf_node+1) - m_node_wr), @@ -470,7 +475,7 @@ void tcp_connection::handle_read_status_body( } m_node_wr += bytes_transferred; - int got_bytes = m_node_wr - m_node_rd; + size_t got_bytes = m_node_wr - m_node_rd; BOOST_ASSERT(got_bytes >= 3); if (!this->local_nodename().empty()) { @@ -552,6 +557,7 @@ void tcp_connection::handle_read_challenge_header( m_node_wr += bytes_transferred; m_expect_size = get16be(m_node_rd); + #ifdef EI_DIST_5 unsigned short l_size = (m_dist_version == EI_DIST_5) ? 11 : 19; #else @@ -568,7 +574,8 @@ void tcp_connection::handle_read_challenge_header( return; } - int need_bytes = m_expect_size - (m_node_wr - m_node_rd); + size_t got_bytes = m_node_wr - m_node_rd; + size_t need_bytes = m_expect_size > got_bytes ? m_expect_size - got_bytes : 0; if (need_bytes > 0) { boost::asio::async_read(m_socket, boost::asio::buffer(m_node_wr, (m_buf_node+1) - m_node_wr), @@ -598,9 +605,9 @@ void tcp_connection::handle_read_challenge_body( m_node_wr += bytes_transferred; #ifndef NDEBUG - int got_bytes = m_node_wr - m_node_rd; + size_t got_bytes = m_node_wr - m_node_rd; #endif - BOOST_ASSERT(got_bytes >= (int)m_expect_size); + BOOST_ASSERT(got_bytes >= m_expect_size); char tag = get8(m_node_rd); if (tag != 'n' && tag != 'N') { @@ -645,7 +652,8 @@ void tcp_connection::handle_read_challenge_body( m_node_rd += 4; /* ignore peer 'creation' */ nodename_len = get16be(m_node_rd); - if (nodename_len > m_node_wr - m_node_rd) { + size_t got_bytes = m_node_wr - m_node_rd; + if (nodename_len > got_bytes) { std::stringstream ss; ss << "<- RECV_CHALLENGE 'N' (error) nodename too long from node '" << this->remote_nodename() << "': " << nodename_len; @@ -788,7 +796,8 @@ void tcp_connection::handle_read_challenge_ack_header( m_node_wr = m_buf_node + bytes_transferred; - int need_bytes = m_expect_size - (m_node_wr - m_node_rd); + size_t got_bytes = m_node_wr - m_node_rd; + size_t need_bytes = m_expect_size > got_bytes ? m_expect_size - got_bytes : 0; if (need_bytes > 0) { boost::asio::async_read(m_socket, boost::asio::buffer(m_node_wr, (m_buf_node+1)-m_node_wr), diff --git a/include/eixx/eterm_exception.hpp b/include/eixx/eterm_exception.hpp index b478648..ecf5bc9 100644 --- a/include/eixx/eterm_exception.hpp +++ b/include/eixx/eterm_exception.hpp @@ -168,20 +168,31 @@ class err_encode_exception: public eterm_exception { const char* what() const throw() { return m_what.c_str(); } int code() const { return m_code; } - int value() const { return m_value; } + long value() const { return m_value; } }; /** * Exception while decoding */ -class err_decode_exception: public err_encode_exception { +class err_decode_exception: public eterm_exception { + uintptr_t m_pos; + long m_value; + std::string m_what; public: - err_decode_exception(const std::string &msg, int pos=0) - : err_encode_exception(msg, pos) - {} - err_decode_exception(const std::string &msg, int pos, long value) - : err_encode_exception(msg, pos, value) - {} + err_decode_exception(const std::string &msg, uintptr_t pos=0, long value=0) + : eterm_exception(msg) + , m_pos(pos) + , m_value(value) + { + std::stringstream s; s << m_msg; + if (value != 0) s << " (" << m_value << ")"; + s << " at (" << m_pos << ")"; + m_what = s.str(); + } + + const char* what() const throw() { return m_what.c_str(); } + uintptr_t pos() const { return m_pos; } + long value() const { return m_value; } }; class err_empty_list: public eterm_exception { diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 9e668e5..f0437dd 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -170,7 +170,7 @@ class atom /// Decode an atom from a binary buffer encoded in /// Erlang external binary format. - atom(const char* a_buf, int& idx, size_t a_size) + atom(const char* a_buf, uintptr_t& idx, size_t a_size) { const char *s = a_buf + idx; const char *s0 = s; @@ -182,11 +182,11 @@ class atom BOOST_ASSERT((size_t)idx <= a_size); } - const char* c_str() const { return atom_table()[m_index].c_str(); } - const std::string& to_string() const { return atom_table()[m_index]; } - size_t size() const { return atom_table()[m_index].size(); } - size_t length() const { return size(); } - bool empty() const { return m_index == 0; } + const char* c_str() const { return atom_table()[m_index].c_str(); } + const std::string& to_string() const { return atom_table()[m_index]; } + uint16_t size() const { return (uint16_t)atom_table()[m_index].size(); } + uint16_t length() const { return size(); } + bool empty() const { return m_index == 0; } /// Get atom's index in the atom table. int index() const { return m_index; } @@ -210,30 +210,30 @@ class atom /// Get the size of a buffer needed to encode this atom in /// the external binary format. size_t encode_size() const { - const size_t len = length(); - return (len > 255 ? 3 : 2) + len; + const size_t sz = size(); + return (sz > 255 ? 3 : 2) + sz; } /// Encode the atom in external binary format. /// @param buf is the buffer space to encode the atom to. /// @param idx is the offset in the \a buf where to begin writing. /// @param size is the size of \a buf. - void encode(char* buf, int& idx, size_t size) const { + void encode(char* buf, uintptr_t& idx, size_t a_size) const { char* s = buf + idx; char* s0 = s; - const size_t len = std::min((size_t)MAXATOMLEN_UTF8, length()); + const uint16_t len = std::min((uint16_t)MAXATOMLEN_UTF8, size()); /* This function is documented to truncate at MAXATOMLEN_UTF8 (1021) */ - if (len > 255) { + if (len > UINT8_MAX) { put8(s, ERL_ATOM_UTF8_EXT); put16be(s, len); } else { put8(s, ERL_SMALL_ATOM_UTF8_EXT); - put8(s, len); + put8(s, (uint8_t)len); } memmove(s, c_str(), len); /* unterminated string */ s += len; idx += s-s0; - BOOST_ASSERT((size_t)idx <= size); + BOOST_ASSERT((size_t)idx <= a_size); } /// Write the atom to the \a out stream. diff --git a/include/eixx/marshal/binary.hpp b/include/eixx/marshal/binary.hpp index fa16c8f..5150140 100644 --- a/include/eixx/marshal/binary.hpp +++ b/include/eixx/marshal/binary.hpp @@ -45,7 +45,7 @@ class binary { blob* m_blob; - void decode(const char* buf, int& idx, size_t size); + void decode(const char* buf, uintptr_t& idx, size_t size); public: binary() : m_blob(nullptr) {} @@ -89,7 +89,7 @@ class binary * @param size is the size of \a buf buffer. * @throw err_decode_exception */ - binary(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); + binary(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc = Alloc()); /** Get the size of the data (in bytes) */ size_t size() const { return m_blob ? m_blob->size() : 0; } @@ -128,12 +128,12 @@ class binary } /** Encode binary to a flat buffer. */ - void encode(char* buf, int& idx, size_t size) const; + void encode(char* buf, uintptr_t& idx, size_t size) const; /** Size of binary buffer needed to hold encoded binary. */ size_t encode_size() const { return 5 + size(); } - std::ostream& dump(std::ostream& out, const varbind* binding=NULL) const { + std::ostream& dump(std::ostream& out, const varbind* =NULL) const { bool printable = size() > 1; for (const char* p = data(), *end = data() + size(); printable && p != end; ++p) if (*p < ' ' || *p > '~') diff --git a/include/eixx/marshal/binary.hxx b/include/eixx/marshal/binary.hxx index 0d62169..06e3e2d 100644 --- a/include/eixx/marshal/binary.hxx +++ b/include/eixx/marshal/binary.hxx @@ -34,7 +34,7 @@ namespace eixx { namespace marshal { template -binary::binary(const char* buf, int& idx, size_t size, const Alloc& a_alloc) +binary::binary(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc) { const char* s = buf + idx; const char* s0 = s; @@ -42,7 +42,7 @@ binary::binary(const char* buf, int& idx, size_t size, const Alloc& a_all if (get8(s) != ERL_BINARY_EXT) throw err_decode_exception("Error decoding binary", idx); - size_t sz = get32be(s); + uint32_t sz = get32be(s); m_blob = new blob(sz, a_alloc); ::memcpy(m_blob->data(),s,sz); @@ -51,15 +51,18 @@ binary::binary(const char* buf, int& idx, size_t size, const Alloc& a_all } template -void binary::encode(char* buf, int& idx, size_t size) const +void binary::encode(char* buf, uintptr_t& idx, size_t size) const { char* s = buf + idx; char* s0 = s; put8(s,ERL_BINARY_EXT); - size_t n = this->size(); - put32be(s, n); - memmove(s, this->data(), n); - s += n; + size_t sz = this->size(); + if (sz > UINT32_MAX) + throw err_encode_exception("BINARY_EXT length exceeds maximum"); + uint32_t len = (uint32_t)sz; + put32be(s, len); + memmove(s, this->data(), len); + s += len; idx += s-s0; BOOST_ASSERT((size_t)idx <= size); } diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 3d6e277..0c5471e 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -197,7 +197,7 @@ class eterm { * Decode a term from the Erlang external binary format. * @throw err_decode_exception */ - void decode(const char* a_buf, int& idx, size_t a_size, const Alloc& a_alloc); + void decode(const char* a_buf, uintptr_t& idx, size_t a_size, const Alloc& a_alloc); long& get(long*) { check(LONG); return vt.i; } double& get(double*) { check(DOUBLE); return vt.d; } @@ -317,7 +317,7 @@ class eterm { * @param a_size is the total size of the term stored in \a a_buf buffer. * @param a_alloc is the custom allocator. */ - eterm(const char* a_buf, int& idx, size_t a_size, const Alloc& a_alloc = Alloc()) { + eterm(const char* a_buf, uintptr_t& idx, size_t a_size, const Alloc& a_alloc = Alloc()) { decode(a_buf, idx, a_size, a_alloc); } diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index a6315d0..bb134af 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -42,7 +42,7 @@ inline eterm_type type_string_to_type(const char* s, size_t n) { if (n < 3) return r; - int m = n - 1; + size_t m = n - 1; const char* p = s+1; switch (s[0]) { @@ -219,23 +219,24 @@ std::string eterm::to_string(size_t a_size_limit, const varbind* b template eterm::eterm(const char* a_buf, size_t a_size, const Alloc& a_alloc) { - int idx = 0; + uintptr_t idx = 0; int vsn; - if (ei_decode_version(a_buf, &idx, &vsn) < 0) + if (ei_decode_version(a_buf, (int*)&idx, &vsn) < 0) throw err_decode_exception("Wrong eterm version byte!", vsn); decode(a_buf, idx, a_size, a_alloc); } template -void eterm::decode(const char* a_buf, int& idx, size_t a_size, const Alloc& a_alloc) +void eterm::decode(const char* a_buf, uintptr_t& idx, size_t a_size, const Alloc& a_alloc) { + BOOST_ASSERT(idx <= INT_MAX); if ((size_t)idx == a_size) throw err_decode_exception("Empty term", idx); // check the type of next term: int type, sz; - if (ei_get_type(a_buf, &idx, &type, &sz) < 0) + if (ei_get_type(a_buf, (int*)&idx, &type, &sz) < 0) throw err_decode_exception("Cannot determine term type", idx); switch (type) { @@ -250,7 +251,7 @@ void eterm::decode(const char* a_buf, int& idx, size_t a_size, const Allo #endif case ERL_ATOM_EXT: { int b; - int i = idx; // TODO: Eliminate this variable when there's is a fix for the bug in ei_decode_boolean + int i = (int)idx; // TODO: Eliminate this variable when there's is a fix for the bug in ei_decode_boolean if (ei_decode_boolean(a_buf, &i, &b) < 0) new (this) eterm(atom(a_buf, idx, a_size)); else { @@ -278,7 +279,7 @@ void eterm::decode(const char* a_buf, int& idx, size_t a_size, const Allo case ERL_LARGE_BIG_EXT: case ERL_INTEGER_EXT: { long long l; - if (ei_decode_longlong(a_buf, &idx, &l) < 0) + if (ei_decode_longlong(a_buf, (int*)&idx, &l) < 0) throw err_decode_exception("Failed decoding long value", idx); new (this) eterm((long)l); break; @@ -286,7 +287,7 @@ void eterm::decode(const char* a_buf, int& idx, size_t a_size, const Allo case NEW_FLOAT_EXT: case ERL_FLOAT_EXT: { double d; - if (ei_decode_double(a_buf, &idx, &d) < 0) + if (ei_decode_double(a_buf, (int*)&idx, &d) < 0) throw err_decode_exception("Failed decoding double value", idx); new (this) eterm(d); break; @@ -374,9 +375,11 @@ void eterm::encode(char* a_buf, size_t size, throw err_encode_exception(s.str()); } } - int offset = a_header_size; - if (a_with_version) - ei_encode_version(a_buf, &offset); + uintptr_t offset = a_header_size; + if (a_with_version) { + BOOST_ASSERT(offset <= INT_MAX); + ei_encode_version(a_buf, (int*)&offset); + } visit_eterm_encoder visitor(a_buf, offset, size); visitor.apply_visitor(*this); BOOST_ASSERT((size_t)offset == size); diff --git a/include/eixx/marshal/eterm_format.hxx b/include/eixx/marshal/eterm_format.hxx index de0d8be..6c82286 100644 --- a/include/eixx/marshal/eterm_format.hxx +++ b/include/eixx/marshal/eterm_format.hxx @@ -113,7 +113,7 @@ namespace marshal { { const char* start = *fmt, *p = start; char c; - int len; + uintptr_t len; skip_ws_and_comments(fmt); @@ -175,7 +175,7 @@ namespace marshal { throw err_format_exception("Error parsing quotted atom", start); *fmt = p+1; /* skip last quote */ - int len = p - start; + uintptr_t len = p - start; return atom(start, len); @@ -200,7 +200,9 @@ namespace marshal { else if (c == '.' && !dotp) dotp = true; else if (c == '#') { - base = strtol(start, NULL, 10); + long b = strtol(start, NULL, 10); + BOOST_ASSERT(b <= INT_MAX); + base = (int)b; start = p+1; } else break; @@ -229,7 +231,7 @@ namespace marshal { throw err_format_exception("Error parsing string", start); *fmt = p+1; /* skip last quote */ - int len = p - start; + uintptr_t len = p - start; return eterm(string(start, len, alloc)); } /* pstring */ diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 283a311..721094a 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -178,7 +178,7 @@ class list : protected alloc_base, Alloc> { /** * Decode the list from a binary buffer. */ - explicit list(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); + explicit list(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc = Alloc()); ~list() { release(); } @@ -262,7 +262,7 @@ class list : protected alloc_base, Alloc> { return result; } - void encode(char* buf, int& idx, size_t size) const; + void encode(char* buf, uintptr_t& idx, size_t size) const; bool subst(eterm& out, const varbind* binding) const; diff --git a/include/eixx/marshal/list.hxx b/include/eixx/marshal/list.hxx index 772df61..290c42e 100644 --- a/include/eixx/marshal/list.hxx +++ b/include/eixx/marshal/list.hxx @@ -38,6 +38,7 @@ namespace marshal { template void list::init(const eterm* items, size_t N, const Alloc& alloc) { + BOOST_ASSERT(N <= UINT_MAX); size_t n = N > 0 ? N : 1; m_blob = new blob_t(sizeof(header_t) + n*sizeof(cons_t), alloc); @@ -45,8 +46,8 @@ void list::init(const eterm* items, size_t N, const Alloc& alloc) cons_t* hd = l_header->head; l_header->initialized = true; - l_header->alloc_size = n; - l_header->size = N; + l_header->alloc_size = (unsigned int)n; + l_header->size = (unsigned int)N; for(auto p = items, end = items+N; p != end; ++p, ++hd) { BOOST_ASSERT(p->initialized()); @@ -103,11 +104,12 @@ list::list(const cons_t* a_head, int a_len, const Alloc& alloc) } template -list::list(const char *buf, int& idx, size_t size, const Alloc& a_alloc) +list::list(const char *buf, uintptr_t& idx, size_t size, const Alloc& a_alloc) : base_t(a_alloc) { + BOOST_ASSERT(idx <= INT_MAX); int arity; - if (ei_decode_list_header(buf, &idx, &arity) < 0) + if (ei_decode_list_header(buf, (int*)&idx, &arity) < 0) err_decode_exception("Error decoding list header", idx); // If this is an empty list - no allocation is needed @@ -141,7 +143,7 @@ list::list(const char *buf, int& idx, size_t size, const Alloc& a_alloc) } template -void list::encode(char* buf, int& idx, size_t size) const +void list::encode(char* buf, uintptr_t& idx, size_t size) const { BOOST_ASSERT(initialized()); char* s = buf + idx; @@ -150,7 +152,11 @@ void list::encode(char* buf, int& idx, size_t size) const } else { put8(s,ERL_LIST_EXT); const header_t* l_header = header(); - put32be(s,l_header->size); + auto sz = l_header->size; + if (sz > UINT32_MAX) + throw err_encode_exception("LIST_EXT length exceeds maximum"); + uint32_t len = (uint32_t)sz; + put32be(s, len); idx += 5; for(const cons_t* p = l_header->head; p; p = p->next) { visit_eterm_encoder visitor(buf, idx, size); diff --git a/include/eixx/marshal/map.hpp b/include/eixx/marshal/map.hpp index 5ba67fa..23894ac 100644 --- a/include/eixx/marshal/map.hpp +++ b/include/eixx/marshal/map.hpp @@ -95,9 +95,10 @@ class map { m->insert(pair); } - map(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) { + map(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc = Alloc()) { + BOOST_ASSERT(idx <= INT_MAX); int arity; - if (ei_decode_map_header(buf, &idx, &arity) < 0) + if (ei_decode_map_header(buf, (int*)&idx, &arity) < 0) err_decode_exception("Error decoding tuple header", idx); initialize(a_alloc); auto* m = m_blob->data(); @@ -203,9 +204,13 @@ class map { return result; } - void encode(char* buf, int& idx, size_t size) const { + void encode(char* buf, uintptr_t& idx, size_t size) const { BOOST_ASSERT(m_blob); - ei_encode_map_header(buf, &idx, this->size()); + BOOST_ASSERT(idx <= INT_MAX); + size_t arity = this->size(); + if (arity > INT_MAX) + throw err_encode_exception("MAP_EXT arity exceeds maximum supported"); + ei_encode_map_header(buf, (int*)&idx, (int)arity); for(auto it = begin(), iend=end(); it != iend; ++it) { visit_eterm_encoder key_visitor(buf, idx, size); key_visitor.apply_visitor(it->first); diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index 31d9543..0f0f133 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -90,7 +90,7 @@ class epid { /// @throw err_decode_exception /// @throw err_bad_argument - void decode(const char* buf, int& idx, size_t size, const Alloc& a_alloc); + void decode(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc); public: @@ -125,7 +125,7 @@ class epid { } /// Decode the pid from a binary buffer. - epid(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()) { + epid(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc = Alloc()) { decode(buf, idx, size, a_alloc); } @@ -207,9 +207,9 @@ class epid { } size_t encode_size() const { return (creation() > 0x03 ? 16 : 13) + node().size(); } - void encode(char* buf, int& idx, size_t size) const; + void encode(char* buf, uintptr_t& idx, size_t size) const; - std::ostream& dump(std::ostream& out, const varbind* binding=NULL) const { + std::ostream& dump(std::ostream& out, const varbind* =NULL) const { out << "#Pid<" << node() << '.' << id() << '.' << serial(); if (creation() > 0) diff --git a/include/eixx/marshal/pid.hxx b/include/eixx/marshal/pid.hxx index 1a786a1..5657ac6 100644 --- a/include/eixx/marshal/pid.hxx +++ b/include/eixx/marshal/pid.hxx @@ -33,7 +33,7 @@ namespace eixx { namespace marshal { template -void epid::decode(const char *buf, int& idx, size_t size, const Alloc& alloc) +void epid::decode(const char *buf, uintptr_t& idx, size_t size, const Alloc& alloc) { const char* s = buf + idx; const char* s0 = s; @@ -68,7 +68,7 @@ void epid::decode(const char *buf, int& idx, size_t size, const Alloc& al } template -void epid::encode(char* buf, int& idx, size_t size) const +void epid::encode(char* buf, uintptr_t& idx, size_t size) const { char* s = buf + idx; char* s0 = s; @@ -80,8 +80,8 @@ void epid::encode(char* buf, int& idx, size_t size) const #else put8(s, ERL_ATOM_EXT); #endif - const std::string& nd = node().to_string(); - unsigned short n = nd.size(); + atom nd = node(); + uint16_t n = nd.size(); put16be(s, n); memmove(s, nd.c_str(), n); s += n; diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index 77b9f19..ce7ab4c 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -107,7 +107,7 @@ class port { * @param size is the size of the \a buf buffer. * @param a_alloc is the allocator to use. */ - port(const char *buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); + port(const char *buf, uintptr_t& idx, size_t size, const Alloc& a_alloc = Alloc()); port(const port& rhs) : m_blob(rhs.m_blob) { if (m_blob) m_blob->inc_rc(); } port(port&& rhs) : m_blob(rhs.m_blob) { rhs.m_blob = nullptr; } @@ -165,9 +165,9 @@ class port { size_t encode_size() const { return (id() > 0x0fffffff ? 16 : creation() > 0x03 ? 12 : 9) + node().size(); } - void encode(char* buf, int& idx, size_t size) const; + void encode(char* buf, uintptr_t& idx, size_t size) const; - std::ostream& dump(std::ostream& out, const varbind* binding=NULL) const { + std::ostream& dump(std::ostream& out, const varbind* =NULL) const { return out << *this; } }; diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index 3eb76df..f448f70 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -33,7 +33,7 @@ namespace eixx { namespace marshal { template -port::port(const char *buf, int& idx, size_t size, const Alloc& a_alloc) +port::port(const char *buf, uintptr_t& idx, size_t size, const Alloc& a_alloc) { const char* s = buf + idx; const char* s0 = s; @@ -83,7 +83,7 @@ port::port(const char *buf, int& idx, size_t size, const Alloc& a_alloc) } template -void port::encode(char* buf, int& idx, size_t size) const +void port::encode(char* buf, uintptr_t& idx, size_t size) const { char* s = buf + idx; char* s0 = s; @@ -95,10 +95,10 @@ void port::encode(char* buf, int& idx, size_t size) const #else put8(s, ERL_ATOM_EXT); #endif - const std::string& str = node().to_string(); - unsigned short n = str.size(); + atom nd = node(); + uint16_t n = nd.size(); put16be(s, n); - memmove(s, str.c_str(), n); + memmove(s, nd.c_str(), n); s += n; /* the integers */ @@ -126,7 +126,7 @@ void port::encode(char* buf, int& idx, size_t size) const #endif *s0 = ERL_PORT_EXT; put32be(s, id() & 0x0fffffff /* 28 bits */); - put8(s, l_cre); + put8(s, l_cre & 0x03 /* 2 bits */); #if defined(ERL_V4_PORT_EXT) || defined(ERL_NEW_PORT_EXT) } #endif diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index fb44088..867f8df 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -51,11 +51,11 @@ class ref { struct ref_blob { atom node; - uint32_t len; + uint16_t len; uint32_t ids[COUNT]; uint32_t creation; - ref_blob(const atom& a_node, const uint32_t* a_ids, size_t n, uint32_t a_cre) + ref_blob(const atom& a_node, const uint32_t* a_ids, uint16_t n, uint32_t a_cre) : node(a_node) , len(n) , creation(a_cre) @@ -82,7 +82,7 @@ class ref { blob* m_blob; // Must only be called from constructor! - void init(const atom& a_node, const uint32_t* a_ids, size_t n, uint32_t a_cre, + void init(const atom& a_node, const uint32_t* a_ids, uint16_t n, uint32_t a_cre, const Alloc& alloc) { detail::check_node_length(a_node.size()); @@ -153,7 +153,7 @@ class ref { * @param size is the size of the \a buf buffer. * @param a_alloc is the allocator to use. */ - ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); + ref(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc = Alloc()); ref(const ref& rhs) : m_blob(rhs.m_blob) { if (m_blob) m_blob->inc_rc(); } ref(ref&& rhs) : m_blob(rhs.m_blob) { rhs.m_blob = nullptr; } @@ -201,7 +201,7 @@ class ref { * Get the id array from the REF. * @return the id array number from the REF. */ - const size_t len() const { return m_blob ? m_blob->data()->len : 0; } + uint16_t len() const { return m_blob ? m_blob->data()->len : 0; } /** * Get the creation number from the REF. @@ -220,7 +220,7 @@ class ref { int n = node().compare(rhs.node()); if (n != 0) return n < 0; auto e = std::min(len(), rhs.len()); - for (size_t i=0; i < e; ++i) { + for (uint32_t i=0; i < e; ++i) { auto i1 = id(i); auto i2 = rhs.id(i); if (i1 > i2) return false; @@ -236,9 +236,9 @@ class ref { size_t encode_size() const { return 1+2+(3+node().size()) + len()*4 + (creation() > 0x03 ? 4 : 1); } - void encode(char* buf, int& idx, size_t size) const; + void encode(char* buf, uintptr_t& idx, size_t size) const; - std::ostream& dump(std::ostream& out, const varbind* binding=nullptr) const { + std::ostream& dump(std::ostream& out, const varbind* =nullptr) const { return out << *this; } }; diff --git a/include/eixx/marshal/ref.hxx b/include/eixx/marshal/ref.hxx index 2780d8f..85ad081 100644 --- a/include/eixx/marshal/ref.hxx +++ b/include/eixx/marshal/ref.hxx @@ -35,7 +35,7 @@ namespace eixx { namespace marshal { template -ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) +ref::ref(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t size, const Alloc& a_alloc) { const char *s = buf + idx; const char *s0 = s; @@ -47,8 +47,8 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) #endif #ifdef ERL_NEW_REFERENCE_EXT case ERL_NEW_REFERENCE_EXT: { - int count = get16be(s); // First goes the count - if (count < 0 || count > COUNT) + uint16_t count = get16be(s); // First goes the count + if (count > COUNT) throw err_decode_exception("Error decoding ref's count", idx+1, count); int len = atom::get_len(s); @@ -97,7 +97,7 @@ ref::ref(const char* buf, int& idx, size_t size, const Alloc& a_alloc) } template -void ref::encode(char* buf, int& idx, size_t size) const +void ref::encode(char* buf, uintptr_t& idx, size_t size) const { char* s = buf + idx; char* s0 = s; @@ -112,10 +112,10 @@ void ref::encode(char* buf, int& idx, size_t size) const #else put8(s, ERL_ATOM_EXT); #endif - const std::string& str = node().to_string(); - unsigned short n = str.size(); + atom nd = node(); + uint16_t n = nd.size(); put16be(s, n); - memmove(s, str.c_str(), n); + memmove(s, nd.c_str(), n); s += n; /* the integers */ diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index d995d2d..779d760 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -105,7 +105,7 @@ class string s.m_blob = nullptr; } - string(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); + string(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc = Alloc()); ~string() { release(); @@ -182,8 +182,12 @@ class string return n == 0 ? 1 : n + (n <= 0xffff ? 3 : 5+n+1); } - void encode(char* buf, int& idx, size_t size) const { - ei_encode_string_len(buf, &idx, c_str(), length()); + void encode(char* buf, uintptr_t& idx, size_t) const { + BOOST_ASSERT(idx <= INT_MAX); + size_t len = size(); + if (len > INT_MAX) + throw err_encode_exception("STRING_EXT length exceeds maximum"); + ei_encode_string_len(buf, (int*)&idx, c_str(), (int)len); } template @@ -193,7 +197,7 @@ class string std::string to_binary_string() const { return eixx::to_binary_string(c_str(), size()); } - std::ostream& dump(std::ostream& out, const varbind* binding=NULL) const { + std::ostream& dump(std::ostream& out, const varbind* =NULL) const { return out << *this; } }; @@ -204,7 +208,7 @@ static std::string to_binary_string(const string& a) { } template -string::string(const char* buf, int& idx, size_t size, const Alloc& a_alloc) +string::string(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t size, const Alloc& a_alloc) { const char *s = buf + idx; const char *s0 = s; diff --git a/include/eixx/marshal/trace.hpp b/include/eixx/marshal/trace.hpp index 0fd42bb..296680a 100644 --- a/include/eixx/marshal/trace.hpp +++ b/include/eixx/marshal/trace.hpp @@ -55,7 +55,7 @@ class trace : protected tuple { /// Increment the serial number. This method is not atomic. void inc_serial() { long n = serial(); (*this)[4] = n; (*this)[2] = n+1; } - void check_clock(uint32_t& clock) { + void check_clock(long& clock) { long n = serial(); if (n > clock) (*this)[4] = clock = n; } @@ -77,7 +77,7 @@ class trace : protected tuple { } /// Decode the pid from a binary buffer. - trace(const char* buf, int& idx, size_t a_size, const Alloc& a_alloc = Alloc()) + trace(const char* buf, uintptr_t& idx, size_t a_size, const Alloc& a_alloc = Alloc()) : tuple(buf, idx, a_size, a_alloc) { if (size() != 5 || (*this)[0].type() != LONG @@ -124,11 +124,11 @@ class trace : protected tuple { size_t encode_size() const { return tuple::encode_size(); } - void encode(char* buf, int& idx, size_t size) const { + void encode(char* buf, uintptr_t& idx, size_t size) const { tuple::encode(buf, idx, size); } - std::ostream& dump(std::ostream& out, const varbind* binding=NULL) const { + std::ostream& dump(std::ostream& out, const varbind* =NULL) const { return out << *static_cast*>(this); } @@ -136,7 +136,7 @@ class trace : protected tuple { static trace* tracer(trace_op op, const trace* token = NULL) { static trace save_token; static bool tracing = false; - static uint32_t clock = 0; + static long clock = 0; switch (op) { case TRACE_OFF: tracing = false; break; diff --git a/include/eixx/marshal/tuple.hpp b/include/eixx/marshal/tuple.hpp index d0af77f..f9765e6 100644 --- a/include/eixx/marshal/tuple.hpp +++ b/include/eixx/marshal/tuple.hpp @@ -124,7 +124,7 @@ class tuple { /** * Decode the tuple from a binary buffer. */ - tuple(const char* buf, int& idx, size_t size, const Alloc& a_alloc = Alloc()); + tuple(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc = Alloc()); ~tuple() { release(); @@ -176,13 +176,13 @@ class tuple { return true; } - const eterm& operator[] (int idx) const { - BOOST_ASSERT(m_blob && (size_t)idx < size()); + const eterm& operator[] (size_t idx) const { + BOOST_ASSERT(m_blob && idx < size()); return m_blob->data()[idx]; } - eterm& operator[] (int idx) { - BOOST_ASSERT(m_blob && (size_t)idx < size()); + eterm& operator[] (size_t idx) { + BOOST_ASSERT(m_blob && idx < size()); return m_blob->data()[idx]; } @@ -213,7 +213,7 @@ class tuple { return result; } - void encode(char* buf, int& idx, size_t size) const; + void encode(char* buf, uintptr_t& idx, size_t size) const; bool subst(eterm& out, const varbind* binding) const; diff --git a/include/eixx/marshal/tuple.hxx b/include/eixx/marshal/tuple.hxx index 8310b4c..11580d6 100644 --- a/include/eixx/marshal/tuple.hxx +++ b/include/eixx/marshal/tuple.hxx @@ -37,10 +37,11 @@ namespace eixx { namespace marshal { template -tuple::tuple(const char* buf, int& idx, size_t size, const Alloc& a_alloc) +tuple::tuple(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc) { + BOOST_ASSERT(idx <= INT_MAX); int arity; - if (ei_decode_tuple_header(buf, &idx, &arity) < 0) + if (ei_decode_tuple_header(buf, (int*)&idx, &arity) < 0) err_decode_exception("Error decoding tuple header", idx); m_blob = new blob, Alloc>(arity+1, a_alloc); for (int i=0; i < arity; i++) { @@ -51,10 +52,14 @@ tuple::tuple(const char* buf, int& idx, size_t size, const Alloc& a_alloc } template -void tuple::encode(char* buf, int& idx, size_t size) const +void tuple::encode(char* buf, uintptr_t& idx, size_t size) const { BOOST_ASSERT(initialized()); - ei_encode_tuple_header(buf, &idx, this->size()); + BOOST_ASSERT(idx <= INT_MAX); + size_t arity = this->size(); + if (arity > INT_MAX) + throw err_encode_exception("LARGE_TUPLE_EXT arity exceeds maximum supported"); + ei_encode_tuple_header(buf, (int*)&idx, (int)arity); for(const_iterator it = begin(), iend=end(); it != iend; ++it) { visit_eterm_encoder visitor(buf, idx, size); visitor.apply_visitor(*it); diff --git a/include/eixx/marshal/var.hpp b/include/eixx/marshal/var.hpp index 5a75d54..bc02446 100644 --- a/include/eixx/marshal/var.hpp +++ b/include/eixx/marshal/var.hpp @@ -96,7 +96,7 @@ class var size_t encode_size() const { throw err_encode_exception("Cannot encode vars!"); } - void encode(char* buf, int& idx, size_t size) const { + void encode(char*, uintptr_t&, size_t) const { throw err_encode_exception("Cannot encode vars!"); } diff --git a/include/eixx/marshal/visit_encode_size.hpp b/include/eixx/marshal/visit_encode_size.hpp index 7458b47..a9121e5 100644 --- a/include/eixx/marshal/visit_encode_size.hpp +++ b/include/eixx/marshal/visit_encode_size.hpp @@ -39,7 +39,7 @@ struct visit_eterm_encode_size_calc : public static_visitor, size_t> { size_t operator()(bool a) const { return 2 + (a ? 4 : 5); } - size_t operator()(double a) const { return 9; } + size_t operator()(double ) const { return 9; } size_t operator()(long a) const { int n = 0; ei_encode_longlong(NULL, &n, a); return n; } template diff --git a/include/eixx/marshal/visit_encoder.hpp b/include/eixx/marshal/visit_encoder.hpp index 04b65a5..f2bc1fa 100644 --- a/include/eixx/marshal/visit_encoder.hpp +++ b/include/eixx/marshal/visit_encoder.hpp @@ -35,16 +35,25 @@ namespace marshal { class visit_eterm_encoder: public static_visitor { mutable char* buf; - int& idx; + uintptr_t& idx; const size_t size; public: - visit_eterm_encoder(char* a_buf, int& a_idx, size_t a_size) + visit_eterm_encoder(char* a_buf, uintptr_t& a_idx, size_t a_size) : buf(a_buf), idx(a_idx), size(a_size) {} - void operator() (bool a) const { ei_encode_boolean (buf, &idx, a); } - void operator() (long a) const { ei_encode_longlong(buf, &idx, a); } - void operator() (double a) const { ei_encode_double (buf, &idx, a); } + void operator() (bool a) const { + BOOST_ASSERT(idx <= INT_MAX); + ei_encode_boolean(buf, (int*)&idx, a); + } + void operator() (long a) const { + BOOST_ASSERT(idx <= INT_MAX); + ei_encode_longlong(buf, (int*)&idx, a); + } + void operator() (double a) const { + BOOST_ASSERT(idx <= INT_MAX); + ei_encode_double(buf, (int*)&idx, a); + } template void operator()(const T& a) const { a.encode(buf, idx, size); } diff --git a/include/eixx/marshal/visit_subst.hpp b/include/eixx/marshal/visit_subst.hpp index c263cb9..025549c 100644 --- a/include/eixx/marshal/visit_subst.hpp +++ b/include/eixx/marshal/visit_subst.hpp @@ -52,7 +52,7 @@ class visit_eterm_subst bool operator()(const var& a) const { return a.subst(m_out, m_binding); } template - bool operator()(const T& a) const { return false; } + bool operator()(const T&) const { return false; } }; } // namespace eixx diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index 63fab93..c6a7299 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -69,7 +69,7 @@ struct async_queue : boost::enable_shared_from_this> // Dequeue up to m_batch_size of items and for each one call // m_wait_handler template - void process_queue(const Handler& h, const boost::system::error_code& ec, + void process_queue(const Handler& h, [[maybe_unused]] const boost::system::error_code& ec, std::chrono::milliseconds repeat, int repeat_count) { // Process up to m_batch_size items waiting on the queue. // For each dequeued item call m_wait_handler diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index 4c066d9..d8320e9 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -136,7 +136,7 @@ namespace util { int lookup(const char* a_name) { return lookup(String(a_name)); } int lookup(const String& a_name) { - auto n = try_lookup(a_name); + int n = try_lookup(a_name); if (n >= 0) return n; if (n == -2) throw err_bad_argument("Atom size is too long!"); @@ -148,9 +148,10 @@ namespace util { return n; } - n = m_atoms.size(); - if ((size_t)(n+1) == m_atoms.capacity()) + size_t sz = m_atoms.size(); + if (sz > INT_MAX || sz == m_atoms.capacity()) throw std::runtime_error("Atom hash table is full!"); + n = (int)sz; m_atoms.push_back(a_name); m_index[m_atoms.back().c_str()] = n; return n; diff --git a/include/eixx/util/hashtable.hpp b/include/eixx/util/hashtable.hpp index 2ccdf7a..6ff9cbd 100644 --- a/include/eixx/util/hashtable.hpp +++ b/include/eixx/util/hashtable.hpp @@ -56,8 +56,9 @@ struct hsieh_hash_fun { static uint16_t get16bits(const char* d) { return *(const uint16_t *)d; } size_t operator()(const char* data) const { - int len = strlen(data); - uint32_t hash = len, tmp; + size_t len = strlen(data); + BOOST_ASSERT(len <= UINT32_MAX); + uint32_t hash = (uint32_t)len, tmp; int rem; if (len <= 0 || data == NULL) return 0; From 492ce22e0287f8a417057f8073aad553520faeaf Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Thu, 26 Aug 2021 20:05:21 +0800 Subject: [PATCH 168/185] fix err_decode_exception usage & compiler warnings --- .../eixx/connect/transport_otp_connection.hxx | 6 +++--- include/eixx/marshal/alloc_base.hpp | 4 ++-- include/eixx/marshal/atom.hpp | 4 ++-- include/eixx/marshal/binary.hxx | 13 ++++++------ include/eixx/marshal/eterm.hxx | 4 ++-- include/eixx/marshal/pid.hxx | 20 +++++++++---------- include/eixx/marshal/port.hxx | 13 +++++++----- include/eixx/marshal/ref.hxx | 14 ++++++------- include/eixx/marshal/string.hpp | 10 +++++----- include/eixx/marshal/trace.hpp | 2 +- 10 files changed, 47 insertions(+), 43 deletions(-) diff --git a/include/eixx/connect/transport_otp_connection.hxx b/include/eixx/connect/transport_otp_connection.hxx index 9df07bc..f8e6e68 100644 --- a/include/eixx/connect/transport_otp_connection.hxx +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -366,11 +366,11 @@ transport_msg_decode(const char *mbuf, size_t len, transport_msg& a_tm) size_t n = len < 65 ? len : 64; std::string s = std::string("Missing pass-through flag in message") + to_binary_string(mbuf, n); - throw err_decode_exception(s, len); + throw err_decode_exception(s, index, len); } if (unlikely(ei_decode_version(s, (int*)&index, &version) || version != ERL_VERSION_MAGIC)) - throw err_decode_exception("Invalid control message magic number", version); + throw err_decode_exception("Invalid control message magic number", index, version); tuple cntrl(s, index, len, m_allocator); @@ -388,7 +388,7 @@ transport_msg_decode(const char *mbuf, size_t len, transport_msg& a_tm) if (likely((1 << msgtype) & types_with_payload)) { BOOST_ASSERT(index <= INT_MAX); if (unlikely(ei_decode_version(s, (int*)&index, &version)) || unlikely((version != ERL_VERSION_MAGIC))) - throw err_decode_exception("Invalid message magic number", version); + throw err_decode_exception("Invalid message magic number", index, version); eterm msg(s, index, len, m_allocator); a_tm.set(msgtype, cntrl, &msg); diff --git a/include/eixx/marshal/alloc_base.hpp b/include/eixx/marshal/alloc_base.hpp index bf11acc..e964089 100644 --- a/include/eixx/marshal/alloc_base.hpp +++ b/include/eixx/marshal/alloc_base.hpp @@ -143,14 +143,14 @@ namespace marshal { /// This method overrides the new() operator for this class /// so that the blob memory is taken from the Alloc allocator. - static void* operator new(size_t sz) { + static void* operator new([[maybe_unused]] size_t sz) { BOOST_ASSERT(sz == sizeof(blob)); return get_blob_alloc().allocate(1); } /// This method overrides the new() operator for this class /// so that the blob memory is released to the Alloc allocator. - static void operator delete(void* p, size_t sz) { + static void operator delete(void* p, [[maybe_unused]] size_t sz) { BOOST_ASSERT(sz == sizeof(blob)); get_blob_alloc().deallocate(static_cast*>(p), 1); } diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index f0437dd..d283aa0 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -170,7 +170,7 @@ class atom /// Decode an atom from a binary buffer encoded in /// Erlang external binary format. - atom(const char* a_buf, uintptr_t& idx, size_t a_size) + atom(const char* a_buf, uintptr_t& idx, [[maybe_unused]] size_t a_size) { const char *s = a_buf + idx; const char *s0 = s; @@ -218,7 +218,7 @@ class atom /// @param buf is the buffer space to encode the atom to. /// @param idx is the offset in the \a buf where to begin writing. /// @param size is the size of \a buf. - void encode(char* buf, uintptr_t& idx, size_t a_size) const { + void encode(char* buf, uintptr_t& idx, [[maybe_unused]] size_t a_size) const { char* s = buf + idx; char* s0 = s; const uint16_t len = std::min((uint16_t)MAXATOMLEN_UTF8, size()); diff --git a/include/eixx/marshal/binary.hxx b/include/eixx/marshal/binary.hxx index 06e3e2d..ff2fa37 100644 --- a/include/eixx/marshal/binary.hxx +++ b/include/eixx/marshal/binary.hxx @@ -34,13 +34,14 @@ namespace eixx { namespace marshal { template -binary::binary(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc) +binary::binary(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t size, const Alloc& a_alloc) { - const char* s = buf + idx; - const char* s0 = s; + const char* s = buf + idx; + const char* s0 = s; + uint8_t tag = get8(s); - if (get8(s) != ERL_BINARY_EXT) - throw err_decode_exception("Error decoding binary", idx); + if (tag != ERL_BINARY_EXT) + throw err_decode_exception("Error decoding binary's type", idx, tag); uint32_t sz = get32be(s); m_blob = new blob(sz, a_alloc); @@ -51,7 +52,7 @@ binary::binary(const char* buf, uintptr_t& idx, size_t size, const Alloc& } template -void binary::encode(char* buf, uintptr_t& idx, size_t size) const +void binary::encode(char* buf, uintptr_t& idx, [[maybe_unused]] size_t size) const { char* s = buf + idx; char* s0 = s; diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index bb134af..fdb9aa1 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -222,7 +222,7 @@ eterm::eterm(const char* a_buf, size_t a_size, const Alloc& a_alloc) uintptr_t idx = 0; int vsn; if (ei_decode_version(a_buf, (int*)&idx, &vsn) < 0) - throw err_decode_exception("Wrong eterm version byte!", vsn); + throw err_decode_exception("Wrong eterm version byte!", idx, vsn); decode(a_buf, idx, a_size, a_alloc); } @@ -328,7 +328,7 @@ void eterm::decode(const char* a_buf, uintptr_t& idx, size_t a_size, cons default: std::ostringstream oss; oss << "Unknown message content type " << type; - throw err_decode_exception(oss.str()); + throw err_decode_exception(oss.str(), idx, type); break; } } diff --git a/include/eixx/marshal/pid.hxx b/include/eixx/marshal/pid.hxx index 7c75941..7c6c411 100644 --- a/include/eixx/marshal/pid.hxx +++ b/include/eixx/marshal/pid.hxx @@ -33,21 +33,21 @@ namespace eixx { namespace marshal { template -void epid::decode(const char *buf, uintptr_t& idx, size_t size, const Alloc& alloc) +void epid::decode(const char *buf, uintptr_t& idx, [[maybe_unused]] size_t size, const Alloc& alloc) { - const char* s = buf + idx; - const char* s0 = s; - auto n = get8(s); - if (n != ERL_PID_EXT + const char* s = buf + idx; + const char* s0 = s; + uint8_t tag = get8(s); + if (tag != ERL_PID_EXT #ifdef ERL_NEW_PID_EXT - && n != ERL_NEW_PID_EXT + && tag != ERL_NEW_PID_EXT #endif ) - throw err_decode_exception("Error decoding pid", n); + throw err_decode_exception("Error decoding pid's type", idx, tag); int len = atom::get_len(s); if (len < 0) - throw err_decode_exception("Error decoding pid node", -1); + throw err_decode_exception("Error decoding pid node", idx, len); detail::check_node_length(len); atom l_node(s, len); @@ -56,7 +56,7 @@ void epid::decode(const char *buf, uintptr_t& idx, size_t size, const All uint32_t l_id = get32be(s); /* 15 bits if distribution flag DFLAG_V4_NC is not set */ uint32_t l_ser = get32be(s); /* 13 bits if distribution flag DFLAG_V4_NC is not set */ #ifdef ERL_NEW_PID_EXT - uint32_t l_cre = n == ERL_NEW_PID_EXT ? get32be(s) : (get8(s) & 0x03); + uint32_t l_cre = tag == ERL_NEW_PID_EXT ? get32be(s) : (get8(s) & 0x03); #else uint32_t l_cre = get8(s) & 0x03; /* 2 bits */ #endif @@ -68,7 +68,7 @@ void epid::decode(const char *buf, uintptr_t& idx, size_t size, const All } template -void epid::encode(char* buf, uintptr_t& idx, size_t size) const +void epid::encode(char* buf, uintptr_t& idx, [[maybe_unused]] size_t size) const { char* s = buf + idx; char* s0 = s; diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index 35199ca..2fff1da 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -33,11 +33,11 @@ namespace eixx { namespace marshal { template -port::port(const char *buf, uintptr_t& idx, size_t size, const Alloc& a_alloc) +port::port(const char *buf, uintptr_t& idx, [[maybe_unused]] size_t size, const Alloc& a_alloc) { const char* s = buf + idx; const char* s0 = s; - auto tag = get8(s); + uint8_t tag = get8(s); if (tag != ERL_PORT_EXT #ifdef ERL_NEW_PORT_EXT && tag != ERL_NEW_PORT_EXT @@ -46,11 +46,11 @@ port::port(const char *buf, uintptr_t& idx, size_t size, const Alloc& a_a && tag != ERL_V4_PORT_EXT #endif ) - throw err_decode_exception("Error decoding port", idx, tag); + throw err_decode_exception("Error decoding port's type", idx, tag); int len = atom::get_len(s); if (len < 0) - throw err_decode_exception("Error decoding port node", idx, len); + throw err_decode_exception("Error decoding port's node", idx, len); detail::check_node_length(len); atom l_node(s, len); s += len; @@ -75,6 +75,9 @@ port::port(const char *buf, uintptr_t& idx, size_t size, const Alloc& a_a id = uint64_t(get32be(s) & 0x0fffffff); /* 28 bits */ cre = get8(s) & 0x03; /* 2 bits */ break; + + default: + throw err_decode_exception("Error decoding port's type", idx, tag); } init(l_node, id, cre, a_alloc); @@ -83,7 +86,7 @@ port::port(const char *buf, uintptr_t& idx, size_t size, const Alloc& a_a } template -void port::encode(char* buf, uintptr_t& idx, size_t size) const +void port::encode(char* buf, uintptr_t& idx, [[maybe_unused]] size_t size) const { char* s = buf + idx; char* s0 = s; diff --git a/include/eixx/marshal/ref.hxx b/include/eixx/marshal/ref.hxx index 9aba064..94c70c0 100644 --- a/include/eixx/marshal/ref.hxx +++ b/include/eixx/marshal/ref.hxx @@ -37,11 +37,11 @@ namespace marshal { template ref::ref(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t size, const Alloc& a_alloc) { - const char *s = buf + idx; + const char *s = buf + idx; const char *s0 = s; - int type = get8(s); + uint8_t tag = get8(s); - switch (type) { + switch (tag) { #ifdef ERL_NEWER_REFERENCE_EXT case ERL_NEWER_REFERENCE_EXT: #endif @@ -59,7 +59,7 @@ ref::ref(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t size, c s += len; uint32_t cre, mask; - std::tie(cre, mask) = type == ERL_NEW_REFERENCE_EXT + std::tie(cre, mask) = tag == ERL_NEW_REFERENCE_EXT ? std::make_pair((get8(s) & 0x03u), 0x0003ffffu) /* 18 bits */ : std::make_pair(uint32_t(get32be(s)), 0xFFFFffff); @@ -82,7 +82,7 @@ ref::ref(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t size, c s += len; uint32_t id = get32be(s) & 0x0003ffff; /* 18 bits */ - uint32_t cre = get8(s) & 0x03; + uint32_t cre = get8(s) & 0x03; /* 2 bits */ init(nd, &id, 1u, cre, a_alloc); @@ -90,12 +90,12 @@ ref::ref(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t size, c break; } default: - throw err_decode_exception("Error decoding ref's type", type); + throw err_decode_exception("Error decoding ref's type", idx, tag); } } template -void ref::encode(char* buf, uintptr_t& idx, size_t size) const +void ref::encode(char* buf, uintptr_t& idx, [[maybe_unused]] size_t size) const { char* s = buf + idx; char* s0 = s; diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index 779d760..4764fc5 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -210,11 +210,11 @@ static std::string to_binary_string(const string& a) { template string::string(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t size, const Alloc& a_alloc) { - const char *s = buf + idx; + const char *s = buf + idx; const char *s0 = s; - int etype = get8(s); + uint8_t tag = get8(s); - switch (etype) { + switch (tag) { case ERL_STRING_EXT: { int len = get16be(s); if (len == 0) @@ -239,7 +239,7 @@ string::string(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t s else { m_blob = new blob(len+1, a_alloc); for (int i=0; idata()[i] = get8(s); } @@ -252,7 +252,7 @@ string::string(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t s break; default: - throw err_decode_exception("Error decoding string type", etype); + throw err_decode_exception("Error decoding string's type", idx, tag); } idx += s-s0; } diff --git a/include/eixx/marshal/trace.hpp b/include/eixx/marshal/trace.hpp index 296680a..11008cb 100644 --- a/include/eixx/marshal/trace.hpp +++ b/include/eixx/marshal/trace.hpp @@ -85,7 +85,7 @@ class trace : protected tuple { || (*this)[2].type() != LONG || (*this)[3].type() != PID || (*this)[4].type() != LONG) - throw err_decode_exception("Invalid trace token type!"); + throw err_decode_exception("Invalid trace token type!", idx); } trace(const trace& rhs) : tuple(rhs) {} From 95b3ef24a5dbf3b9535f698cf2b729433c5621d3 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Thu, 26 Aug 2021 21:33:16 +0800 Subject: [PATCH 169/185] add -Wshadow compiler warnings --- CMakeLists.txt | 4 ++-- include/eixx/connect/transport_otp_connection.hxx | 14 +++++++------- .../eixx/connect/transport_otp_connection_tcp.hxx | 8 ++++---- include/eixx/marshal/pid.hpp | 4 ++-- include/eixx/marshal/ref.hpp | 6 +++--- include/eixx/util/async_queue.hpp | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a6283f..685e490 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ if("${toolchain}" STREQUAL "gcc") if(NOT CMAKE_CXX_COMPILER) set(CMAKE_CXX_COMPILER "g++") endif() - add_definitions(-fopenmp -Wall -Wextra -Wpedantic -Wno-strict-aliasing -Wconversion) + add_definitions(-fopenmp -Wall -Wextra -Wpedantic -Wshadow -Wno-strict-aliasing -Wconversion) if("${CMAKE_BUILD_TYPE}" STREQUAL "release") add_definitions(-flto -funroll-loops -fomit-frame-pointer) @@ -53,7 +53,7 @@ elseif("${toolchain}" STREQUAL "intel") elseif("${toolchain}" STREQUAL "clang") set(CMAKE_C_COMPILER "clang") set(CMAKE_CXX_COMPILER "clang++") - add_definitions(-Wall -Wextra -Wpedantic -Wno-strict-aliasing -Wconversion) + add_definitions(-Wall -Wextra -Wpedantic -Wshadow -Wno-strict-aliasing -Wconversion) else() message(FATAL_ERROR "Invalid toolchain: ${TOOLCHAIN}") endif() diff --git a/include/eixx/connect/transport_otp_connection.hxx b/include/eixx/connect/transport_otp_connection.hxx index f8e6e68..25aa444 100644 --- a/include/eixx/connect/transport_otp_connection.hxx +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -364,9 +364,9 @@ transport_msg_decode(const char *mbuf, size_t len, transport_msg& a_tm) /* pass-through, version, control tuple header, control message type */ if (unlikely(get8(s) != ERL_PASS_THROUGH)) { size_t n = len < 65 ? len : 64; - std::string s = std::string("Missing pass-through flag in message") + std::string str = std::string("Missing pass-through flag in message") + to_binary_string(mbuf, n); - throw err_decode_exception(s, index, len); + throw err_decode_exception(str, index, len); } if (unlikely(ei_decode_version(s, (int*)&index, &version) || version != ERL_VERSION_MAGIC)) @@ -470,11 +470,11 @@ send(const transport_msg& a_msg) a_msg.msg().encode(s + cntrl_sz, msg_sz, 0, true); if (unlikely(verbose() >= VERBOSE_MESSAGE)) { - std::stringstream s; - s << "SEND cntrl=" - << l_cntrl.to_string() << (l_has_msg ? ", msg=" : "") - << (l_has_msg ? a_msg.msg().to_string() : std::string("")); - m_handler->report_status(REPORT_INFO, s.str()); + std::stringstream ss; + ss << "SEND cntrl=" + << l_cntrl.to_string() << (l_has_msg ? ", msg=" : "") + << (l_has_msg ? a_msg.msg().to_string() : std::string("")); + m_handler->report_status(REPORT_INFO, ss.str()); } //if (unlikely(verbose() >= VERBOSE_WIRE)) // std::cout << "SEND " << sz << " bytes " << to_binary_string(data, sz) << std::endl; diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index f2c7de7..c05b542 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -106,8 +106,8 @@ void tcp_connection::handle_resolve( m_state = CS_WAIT_EPMD_CONNECT; auto pthis = this->shared_from_this(); auto epnext = ++ep_iterator; - m_socket.async_connect(m_peer_endpoint, [pthis, epnext](auto& err) { - pthis->handle_epmd_connect(err, epnext); + m_socket.async_connect(m_peer_endpoint, [pthis, epnext](auto& a_err) { + pthis->handle_epmd_connect(a_err, epnext); }); } @@ -151,8 +151,8 @@ void tcp_connection::handle_epmd_connect( auto pthis = this->shared_from_this(); auto epnext = ++ep_iterator; m_socket.async_connect(m_peer_endpoint, - [pthis, epnext](auto& err) { - pthis->handle_epmd_connect(err, epnext); + [pthis, epnext](auto& a_err) { + pthis->handle_epmd_connect(a_err, epnext); }); } else { std::stringstream ss; diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index 8456c06..8512705 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -58,8 +58,8 @@ class epid { : id(a_id), serial(0), creation(a_cre), node(a_node) {} - pid_blob(const atom& a_node, int a_id, int serial, int a_cre) - : id(a_id), serial(serial), creation(a_cre), node(a_node) + pid_blob(const atom& a_node, int a_id, int a_serial, int a_cre) + : id(a_id), serial(a_serial), creation(a_cre), node(a_node) {} }; diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index 3c24296..ac1f2e4 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -71,12 +71,12 @@ class ref { ids[i++] = 0; } template - ref_blob(const atom& node, uint32_t (&ids)[N], uint32_t creation) - : ref_blob(node, ids, N, creation) + ref_blob(const atom& a_node, uint32_t (&a_ids)[N], uint32_t a_cre) + : ref_blob(a_node, a_ids, N, a_cre) {} ref_blob(const atom& a_node, std::initializer_list a_ids, uint32_t a_cre) - : ref_blob(node, &*a_ids.begin(), a_ids.size(), creation) + : ref_blob(a_node, &*a_ids.begin(), a_ids.size(), a_cre) {} }; diff --git a/include/eixx/util/async_queue.hpp b/include/eixx/util/async_queue.hpp index c6a7299..e45ff4c 100644 --- a/include/eixx/util/async_queue.hpp +++ b/include/eixx/util/async_queue.hpp @@ -110,8 +110,8 @@ struct async_queue : boost::enable_shared_from_this> m_timer.expires_from_now(repeat); m_timer.async_wait( [pthis, h, repeat, n] - (const boost::system::error_code& ec) { - (*pthis)(h, ec, repeat, n); + (const boost::system::error_code& a_ec) { + (*pthis)(h, a_ec, repeat, n); }); } } From 8b778bdc385882b48b6edb9ed257ac62cf487a18 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Thu, 26 Aug 2021 10:29:04 -0400 Subject: [PATCH 170/185] Remove inclusion of test_node.cpp from the shared/static lib --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1129e9e..855c26b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,7 +8,6 @@ list(APPEND EIXX_SRCS if (NOT EIXX_MARSHAL_ONLY) list(APPEND EIXX_SRCS basic_otp_node_local.cpp - test_node.cpp ) endif() From 095e29cc247ec11d0065bcc21e85a5c0f2d8ee51 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Sat, 28 Aug 2021 00:20:18 +0800 Subject: [PATCH 171/185] fix Wsign-conversion warnings --- CMakeLists.txt | 4 +- include/eixx/connect/basic_otp_node.hpp | 4 +- include/eixx/connect/basic_otp_node.hxx | 4 +- .../eixx/connect/detail/basic_rpc_server.hpp | 8 ++-- .../eixx/connect/transport_otp_connection.hpp | 2 +- .../eixx/connect/transport_otp_connection.hxx | 10 ++--- .../connect/transport_otp_connection_tcp.hpp | 2 +- .../connect/transport_otp_connection_tcp.hxx | 40 +++++++++---------- include/eixx/marshal/alloc_base.hpp | 8 ++-- include/eixx/marshal/atom.hpp | 22 +++++----- include/eixx/marshal/binary.hxx | 6 +-- include/eixx/marshal/eterm.hxx | 6 +-- include/eixx/marshal/eterm_format.hxx | 10 ++--- include/eixx/marshal/eterm_match.hpp | 2 +- include/eixx/marshal/list.hpp | 8 ++-- include/eixx/marshal/list.hxx | 12 +++--- include/eixx/marshal/pid.hpp | 16 ++++---- include/eixx/marshal/pid.hxx | 12 +++--- include/eixx/marshal/port.hpp | 4 +- include/eixx/marshal/port.hxx | 18 +++++---- include/eixx/marshal/ref.hpp | 8 ++-- include/eixx/marshal/ref.hxx | 22 +++++----- include/eixx/marshal/string.hpp | 18 ++++----- include/eixx/marshal/tuple.hpp | 4 +- include/eixx/marshal/tuple.hxx | 8 ++-- include/eixx/marshal/visit_encode_size.hpp | 2 +- include/eixx/util/common.hpp | 2 +- include/eixx/util/hashtable.hpp | 2 +- include/eixx/util/string_util.hpp | 2 +- 29 files changed, 138 insertions(+), 128 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 685e490..7630a71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ if("${toolchain}" STREQUAL "gcc") if(NOT CMAKE_CXX_COMPILER) set(CMAKE_CXX_COMPILER "g++") endif() - add_definitions(-fopenmp -Wall -Wextra -Wpedantic -Wshadow -Wno-strict-aliasing -Wconversion) + add_definitions(-fopenmp -Wall -Wextra -Wpedantic -Wshadow -Wno-strict-aliasing -Wconversion -Wsign-conversion) if("${CMAKE_BUILD_TYPE}" STREQUAL "release") add_definitions(-flto -funroll-loops -fomit-frame-pointer) @@ -53,7 +53,7 @@ elseif("${toolchain}" STREQUAL "intel") elseif("${toolchain}" STREQUAL "clang") set(CMAKE_C_COMPILER "clang") set(CMAKE_CXX_COMPILER "clang++") - add_definitions(-Wall -Wextra -Wpedantic -Wshadow -Wno-strict-aliasing -Wconversion) + add_definitions(-Wall -Wextra -Wpedantic -Wshadow -Wno-strict-aliasing -Wconversion -Wsign-conversion) else() message(FATAL_ERROR "Invalid toolchain: ${TOOLCHAIN}") endif() diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index 99a16c3..6a7d484 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -83,8 +83,8 @@ class basic_otp_node: public basic_otp_node_local { Mutex m_lock; uint32_t m_creation; - std::atomic_int m_pid_count; - std::atomic_int m_port_count; + std::atomic_uint_fast32_t m_pid_count; + std::atomic_uint_fast64_t m_port_count; std::atomic_uint_fast64_t m_refid0; std::atomic_int m_refid1; diff --git a/include/eixx/connect/basic_otp_node.hxx b/include/eixx/connect/basic_otp_node.hxx index f25abc2..00acc1c 100644 --- a/include/eixx/connect/basic_otp_node.hxx +++ b/include/eixx/connect/basic_otp_node.hxx @@ -51,7 +51,7 @@ class basic_otp_node::atom_con_hash_fun { const char* p = getenv("EI_MAX_NODE_CONNECTIONS"); int n = (p && p[0]) ? atoi(p) : 1024; if (n < 0 || n >= 64*1024) n = 1024; - return n; + return static_cast(n); } public: static size_t get_default_hash_size() { @@ -92,7 +92,7 @@ template epid basic_otp_node:: create_pid() { - int n; + uint32_t n; while (true) { n = m_pid_count.fetch_add(1, std::memory_order_relaxed); if (n < 0x0fffffff /* 28 bits */) break; diff --git a/include/eixx/connect/detail/basic_rpc_server.hpp b/include/eixx/connect/detail/basic_rpc_server.hpp index cf663d0..b67a574 100644 --- a/include/eixx/connect/detail/basic_rpc_server.hpp +++ b/include/eixx/connect/detail/basic_rpc_server.hpp @@ -94,7 +94,7 @@ class basic_otp_node::rpc_server : private Alloc } /// Encode a tuple containing RPC cast details - static tuple encode_rpc_cast(const epid& a_from, + static tuple encode_rpc_cast(const epid& /*a_from*/, const atom& a_mod, const atom& a_fun, const list& a_args, const eterm& a_gleader) @@ -113,9 +113,9 @@ class basic_otp_node::rpc_server : private Alloc return a_msg.match(s_pattern, &binding) ? binding[T] : eterm(); } - bool operator() (const eterm& a_pat, - const varbind& a_binding, - long a_opaque) + bool operator() (const eterm& /*a_pat*/, + const varbind& /*a_binding*/, + long /*a_opaque*/) { // TODO: What do we do on the incoming RPC call? Need to define // afacility to add RPC callable functions diff --git a/include/eixx/connect/transport_otp_connection.hpp b/include/eixx/connect/transport_otp_connection.hpp index dc93492..c3a7999 100644 --- a/include/eixx/connect/transport_otp_connection.hpp +++ b/include/eixx/connect/transport_otp_connection.hpp @@ -207,7 +207,7 @@ class connection size_t available_queue() const { return m_available_queue; } char* rd_ptr() { return m_rd_ptr; } - size_t rd_length() { return m_rd_end - m_rd_ptr; } + size_t rd_length() { return static_cast(m_rd_end - m_rd_ptr); } size_t rd_capacity() { return m_rd_buf.capacity() - rd_length(); } /// Verboseness verbose_type verbose() const { return m_handler->verbose(); } diff --git a/include/eixx/connect/transport_otp_connection.hxx b/include/eixx/connect/transport_otp_connection.hxx index 25aa444..530a0db 100644 --- a/include/eixx/connect/transport_otp_connection.hxx +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -247,7 +247,7 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) // next message. m_packet_size = cast_be(m_rd_ptr); if (m_packet_size > m_rd_buf.capacity()-s_header_size) { - size_t begin_offset = m_rd_ptr - &m_rd_buf[0]; + size_t begin_offset = static_cast(m_rd_ptr - &m_rd_buf[0]); m_rd_buf.reserve(begin_offset + m_packet_size + s_header_size); m_rd_ptr = &m_rd_buf[0] + begin_offset; m_rd_end = m_rd_ptr + len; @@ -312,9 +312,9 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) need_bytes = m_packet_size; } else if ((m_rd_ptr - (&m_rd_buf[0] + s_header_size)) > 0) { // Crunch the buffer by copying leftover bytes to the beginning of the buffer. - const size_t len = m_rd_end - m_rd_ptr; + const size_t len = static_cast(m_rd_end - m_rd_ptr); char* begin = &m_rd_buf[0]; - if (likely((size_t)(m_rd_ptr - begin) < len)) + if (likely(static_cast(m_rd_ptr - begin) < len)) memcpy(begin, m_rd_ptr, len); else memmove(begin, m_rd_ptr, len); @@ -366,7 +366,7 @@ transport_msg_decode(const char *mbuf, size_t len, transport_msg& a_tm) size_t n = len < 65 ? len : 64; std::string str = std::string("Missing pass-through flag in message") + to_binary_string(mbuf, n); - throw err_decode_exception(str, index, len); + throw err_decode_exception(str, index, (long)len); } if (unlikely(ei_decode_version(s, (int*)&index, &version) || version != ERL_VERSION_MAGIC)) @@ -379,7 +379,7 @@ transport_msg_decode(const char *mbuf, size_t len, transport_msg& a_tm) int msgtype = (int)t; if (unlikely(msgtype <= ERL_TICK) || unlikely(msgtype > ERL_MONITOR_P_EXIT)) - throw err_decode_exception("Invalid message type", msgtype); + throw err_decode_exception("Invalid message type", index, msgtype); static const uint32_t types_with_payload = 1 << ERL_SEND | 1 << ERL_REG_SEND diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 488888e..305a153 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -181,7 +181,7 @@ class tcp_connection uint32_t gen_challenge(void); void gen_digest(unsigned challenge, const char cookie[], uint8_t digest[16]); - uint32_t md_32(char* string, int length); + uint32_t md_32(char* string, size_t length); }; } // namespace connect diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index c05b542..4286980 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -363,7 +363,7 @@ void tcp_connection::handle_connect(const boost::system::error_c char* w = m_buf_node; put16be(w, siz - 2); - put8(w, tag); + put8(w, static_cast(tag)); if (tag == 'n') { #ifdef EI_DIST_5 m_dist_version = EI_DIST_5; @@ -433,7 +433,7 @@ void tcp_connection::handle_read_status_header( m_node_rd = m_buf_node; m_expect_size = get16be(m_node_rd); - if (m_expect_size > (size_t)MAXNODELEN + 8 || m_expect_size > (size_t)((m_buf_node+1) - m_node_rd)) { + if (m_expect_size > static_cast(MAXNODELEN + 8) || m_expect_size > static_cast((m_buf_node+1) - m_node_rd)) { std::stringstream ss; ss << "<- RECV_STATUS (error) in status length from node '" << this->remote_nodename() << "': " << m_expect_size; @@ -445,11 +445,11 @@ void tcp_connection::handle_read_status_header( m_node_wr = m_buf_node + bytes_transferred; - size_t got_bytes = m_node_wr - m_node_rd; + size_t got_bytes = static_cast(m_node_wr - m_node_rd); size_t need_bytes = m_expect_size > got_bytes ? m_expect_size - got_bytes : 0; if (need_bytes > 0) { boost::asio::async_read(m_socket, - boost::asio::buffer(m_node_wr, (m_buf_node+1) - m_node_wr), + boost::asio::buffer(m_node_wr, static_cast((m_buf_node+1) - m_node_wr)), boost::asio::transfer_at_least(need_bytes), std::bind(&tcp_connection::handle_read_status_body, shared_from_this(), std::placeholders::_1, @@ -475,7 +475,7 @@ void tcp_connection::handle_read_status_body( } m_node_wr += bytes_transferred; - size_t got_bytes = m_node_wr - m_node_rd; + size_t got_bytes = static_cast(m_node_wr - m_node_rd); BOOST_ASSERT(got_bytes >= 3); if (!this->local_nodename().empty()) { @@ -533,7 +533,7 @@ void tcp_connection::handle_read_status_body( if (got_bytes >= 2) handle_read_challenge_header(boost::system::error_code(), 0); else - boost::asio::async_read(m_socket, boost::asio::buffer(m_node_wr, (m_buf_node+1) - m_node_wr), + boost::asio::async_read(m_socket, boost::asio::buffer(m_node_wr, static_cast((m_buf_node+1) - m_node_wr)), boost::asio::transfer_at_least(2), std::bind(&tcp_connection::handle_read_challenge_header, shared_from_this(), std::placeholders::_1, @@ -564,7 +564,7 @@ void tcp_connection::handle_read_challenge_header( unsigned short l_size = 11; #endif - if (m_expect_size > (size_t)MAXNODELEN + l_size || m_expect_size > (size_t)((m_buf_node+1) - m_node_rd)) { + if (m_expect_size > static_cast(MAXNODELEN + l_size) || m_expect_size > static_cast((m_buf_node+1) - m_node_rd)) { std::stringstream ss; ss << "<- RECV_CHALLENGE (error) in challenge length from node '" << this->remote_nodename() << "': " << m_expect_size; @@ -574,11 +574,11 @@ void tcp_connection::handle_read_challenge_header( return; } - size_t got_bytes = m_node_wr - m_node_rd; + size_t got_bytes = static_cast(m_node_wr - m_node_rd); size_t need_bytes = m_expect_size > got_bytes ? m_expect_size - got_bytes : 0; if (need_bytes > 0) { boost::asio::async_read(m_socket, - boost::asio::buffer(m_node_wr, (m_buf_node+1) - m_node_wr), + boost::asio::buffer(m_node_wr, static_cast((m_buf_node+1) - m_node_wr)), boost::asio::transfer_at_least(need_bytes), std::bind(&tcp_connection::handle_read_challenge_body, shared_from_this(), std::placeholders::_1, @@ -605,11 +605,11 @@ void tcp_connection::handle_read_challenge_body( m_node_wr += bytes_transferred; #ifndef NDEBUG - size_t got_bytes = m_node_wr - m_node_rd; + size_t got_bytes = static_cast(m_node_wr - m_node_rd); #endif BOOST_ASSERT(got_bytes >= m_expect_size); - char tag = get8(m_node_rd); + const char tag = static_cast(get8(m_node_rd)); if (tag != 'n' && tag != 'N') { std::stringstream ss; ss << "<- RECV_CHALLENGE (error) incorrect tag, " @@ -641,7 +641,7 @@ void tcp_connection::handle_read_challenge_body( m_remote_flags = get32be(m_node_rd); m_remote_challenge = get32be(m_node_rd); - nodename_len = m_node_wr - m_node_rd; + nodename_len = static_cast(m_node_wr - m_node_rd); #ifndef EI_DIST_6 } #else @@ -652,7 +652,7 @@ void tcp_connection::handle_read_challenge_body( m_node_rd += 4; /* ignore peer 'creation' */ nodename_len = get16be(m_node_rd); - if (nodename_len > (size_t)(m_node_wr - m_node_rd)) { + if (nodename_len > static_cast(m_node_wr - m_node_rd)) { std::stringstream ss; ss << "<- RECV_CHALLENGE 'N' (error) nodename too long from node '" << this->remote_nodename() << "': " << nodename_len; @@ -712,7 +712,7 @@ void tcp_connection::handle_read_challenge_body( gen_digest(m_remote_challenge, this->m_cookie.c_str(), our_digest); char* w = m_buf_node; - int siz = 0; + size_t siz = 0; // send complement (if dist_version upgraded in-flight) if (m_dist_version > dist_version) { @@ -795,11 +795,11 @@ void tcp_connection::handle_read_challenge_ack_header( m_node_wr = m_buf_node + bytes_transferred; - size_t got_bytes = m_node_wr - m_node_rd; + size_t got_bytes = static_cast(m_node_wr - m_node_rd); size_t need_bytes = m_expect_size > got_bytes ? m_expect_size - got_bytes : 0; if (need_bytes > 0) { boost::asio::async_read(m_socket, - boost::asio::buffer(m_node_wr, (m_buf_node+1)-m_node_wr), + boost::asio::buffer(m_node_wr, static_cast((m_buf_node+1)-m_node_wr)), boost::asio::transfer_at_least(need_bytes), std::bind(&tcp_connection::handle_read_challenge_ack_body, shared_from_this(), @@ -827,11 +827,11 @@ void tcp_connection::handle_read_challenge_ack_body( m_node_wr += bytes_transferred; #ifndef NDEBUG - size_t got_bytes = m_node_wr - m_node_rd; + size_t got_bytes = static_cast(m_node_wr - m_node_rd); #endif BOOST_ASSERT(got_bytes >= m_expect_size); - char tag = get8(m_node_rd); + const char tag = static_cast(get8(m_node_rd)); if (this->handler()->verbose() >= VERBOSE_TRACE) { std::stringstream ss; ss << "<- RECV_CHALLENGE_ACK received (tag=" << tag << "): " @@ -888,7 +888,7 @@ uint32_t tcp_connection::gen_challenge(void) struct timeval tv; clock_t cpu; pid_t pid; - u_long hid; + long hid; uid_t uid; gid_t gid; struct utsname name; @@ -907,7 +907,7 @@ uint32_t tcp_connection::gen_challenge(void) template uint32_t tcp_connection:: -md_32(char* string, int length) +md_32(char* string, size_t length) { BOOST_STATIC_ASSERT(MD5_DIGEST_LENGTH == 16); union { diff --git a/include/eixx/marshal/alloc_base.hpp b/include/eixx/marshal/alloc_base.hpp index e964089..1577a60 100644 --- a/include/eixx/marshal/alloc_base.hpp +++ b/include/eixx/marshal/alloc_base.hpp @@ -80,9 +80,9 @@ namespace marshal { using base_t = typename std::allocator_traits::template rebind_alloc; using blob_alloc_t = typename std::allocator_traits::template rebind_alloc>; - atomic m_rc; - const size_t m_size; - T* m_data; + atomic m_rc; + const size_t m_size; + T* m_data; ~blob() { if (m_data) @@ -130,7 +130,7 @@ namespace marshal { /// Increment internal reference count. void inc_rc() { ++m_rc; } /// Return internal reference count. Use for debugging only. - int use_count() const { return m_rc; } + uint32_t use_count() const { return m_rc; } const Alloc& get_allocator() const { return *reinterpret_cast(this); diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index d283aa0..596b7e1 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -93,7 +93,7 @@ class atom : m_index(atom_table().lookup(std::string(s))) {} /// @copydoc atom::atom - template + template atom(const char (&s)[N]) : m_index(atom_table().lookup(std::string(s, N))) {} @@ -115,8 +115,8 @@ class atom /// Get atom length from a binary buffer encoded in /// Erlang external binary format. - static int get_len(const char*& s) { - switch (get8(s)) { + static long get_len(const char*& s, const uint8_t tag) { + switch (tag) { #ifdef ERL_SMALL_ATOM_UTF8_EXT case ERL_SMALL_ATOM_UTF8_EXT: return get8(s); #endif @@ -127,8 +127,7 @@ class atom case ERL_SMALL_ATOM_EXT: return get8(s); #endif case ERL_ATOM_EXT: return get16be(s); - default: - return -1; + default: return -1; } } @@ -156,9 +155,9 @@ class atom {} /// @copydoc atom::atom - atom(const char* s, int n) : atom(s, size_t(n)) {} + atom(const char* s, int n) : atom(s, static_cast(n)) {} /// @copydoc atom::atom - atom(const char* s, long n) : atom(s, size_t(n)) {} + atom(const char* s, long n) : atom(s, static_cast(n)) {} /// @copydoc atom::atom atom(const char* s, size_t n) : m_index(atom_table().lookup(std::string(s, n))) @@ -174,11 +173,12 @@ class atom { const char *s = a_buf + idx; const char *s0 = s; - int len = get_len(s); + const uint8_t tag = get8(s); + long len = get_len(s, tag); if (len < 0) throw err_decode_exception("Error decoding atom", idx); - m_index = atom_table().lookup(std::string(s, len)); - idx += s + len - s0; + m_index = atom_table().lookup(std::string(s, static_cast(len))); + idx += static_cast(s - s0) + static_cast(len); BOOST_ASSERT((size_t)idx <= a_size); } @@ -232,7 +232,7 @@ class atom } memmove(s, c_str(), len); /* unterminated string */ s += len; - idx += s-s0; + idx += static_cast(s - s0); BOOST_ASSERT((size_t)idx <= a_size); } diff --git a/include/eixx/marshal/binary.hxx b/include/eixx/marshal/binary.hxx index ff2fa37..1a1a0e6 100644 --- a/include/eixx/marshal/binary.hxx +++ b/include/eixx/marshal/binary.hxx @@ -45,9 +45,9 @@ binary::binary(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t s uint32_t sz = get32be(s); m_blob = new blob(sz, a_alloc); - ::memcpy(m_blob->data(),s,sz); + memcpy(m_blob->data(),s,sz); - idx += s + sz - s0; + idx += static_cast(s - s0) + sz; BOOST_ASSERT((size_t)idx <= size); } @@ -64,7 +64,7 @@ void binary::encode(char* buf, uintptr_t& idx, [[maybe_unused]] size_t si put32be(s, len); memmove(s, this->data(), len); s += len; - idx += s-s0; + idx += static_cast(s - s0); BOOST_ASSERT((size_t)idx <= size); } diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index fdb9aa1..e68031a 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -230,7 +230,7 @@ template void eterm::decode(const char* a_buf, uintptr_t& idx, size_t a_size, const Alloc& a_alloc) { BOOST_ASSERT(idx <= INT_MAX); - if ((size_t)idx == a_size) + if (static_cast(idx) == a_size) throw err_decode_exception("Empty term", idx); // check the type of next term: @@ -251,8 +251,8 @@ void eterm::decode(const char* a_buf, uintptr_t& idx, size_t a_size, cons #endif case ERL_ATOM_EXT: { int b; - int i = (int)idx; // TODO: Eliminate this variable when there's is a fix for the bug in ei_decode_boolean - if (ei_decode_boolean(a_buf, &i, &b) < 0) + uintptr_t i = idx; // TODO: Eliminate this variable when there's is a fix for the bug in ei_decode_boolean + if (ei_decode_boolean(a_buf, (int*)&i, &b) < 0) new (this) eterm(atom(a_buf, idx, a_size)); else { idx = i; diff --git a/include/eixx/marshal/eterm_format.hxx b/include/eixx/marshal/eterm_format.hxx index 6c82286..5253401 100644 --- a/include/eixx/marshal/eterm_format.hxx +++ b/include/eixx/marshal/eterm_format.hxx @@ -133,7 +133,7 @@ namespace marshal { for (c = *p; c && isalnum((int)c); c = *(++p)); if (c == '(' && *(p+1) == ')') { - type = type_string_to_type(tps, p - tps); + type = type_string_to_type(tps, static_cast(p - tps)); if (type == UNDEFINED) throw err_format_exception("Error parsing variable type", start); p += 2; @@ -143,7 +143,7 @@ namespace marshal { type = UNDEFINED; *fmt = p; - len = end - start; + len = static_cast(end - start); return var(start, len, type); @@ -175,7 +175,7 @@ namespace marshal { throw err_format_exception("Error parsing quotted atom", start); *fmt = p+1; /* skip last quote */ - uintptr_t len = p - start; + uintptr_t len = static_cast(p - start); return atom(start, len); @@ -231,7 +231,7 @@ namespace marshal { throw err_format_exception("Error parsing string", start); *fmt = p+1; /* skip last quote */ - uintptr_t len = p - start; + uintptr_t len = static_cast(p - start); return eterm(string(start, len, alloc)); } /* pstring */ @@ -383,7 +383,7 @@ namespace marshal { const char* end = strstr(*fmt, "\">>"); if (!end) throw err_format_exception("Cannot find end of binary", *fmt); - ret = eterm(binary(*fmt, end - *fmt, alloc)); + ret = eterm(binary(*fmt, static_cast(end - *fmt), alloc)); *fmt = end + 3; } else { const char* end = strstr(++(*fmt), ">>"); diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index f2d12a7..8b0097d 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -90,7 +90,7 @@ class eterm_pattern_matcher { * is the same as calling eterm_pattern_matcher() and iteratively * adding patterns using push_back() calls. */ - template + template eterm_pattern_matcher( const struct init_struct (&a_patterns)[N], pattern_functor_t a_fun, const Alloc& a_alloc = Alloc()) diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 721094a..1c84251 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -59,8 +59,8 @@ class list : protected alloc_base, Alloc> { , tail (nullptr) {} bool initialized; - unsigned int alloc_size; - unsigned int size; + size_t alloc_size; + size_t size; cons_t* tail; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" @@ -139,7 +139,7 @@ class list : protected alloc_base, Alloc> { /// /// When a_estimated_size is 0, an empty initialized list is created. Otherwise, /// the list is not initialized. - explicit list(int a_estimated_size, const Alloc& alloc = Alloc()) + explicit list(size_t a_estimated_size, const Alloc& alloc = Alloc()) : base_t(alloc) { if (a_estimated_size == 0) @@ -165,7 +165,7 @@ class list : protected alloc_base, Alloc> { explicit list(const cons_t* a_head, int a_len = -1, const Alloc& alloc = Alloc()); - template + template list(const eterm (&items)[N], const Alloc& alloc = Alloc()) : list(items, N, alloc) {} diff --git a/include/eixx/marshal/list.hxx b/include/eixx/marshal/list.hxx index 290c42e..327c056 100644 --- a/include/eixx/marshal/list.hxx +++ b/include/eixx/marshal/list.hxx @@ -38,7 +38,6 @@ namespace marshal { template void list::init(const eterm* items, size_t N, const Alloc& alloc) { - BOOST_ASSERT(N <= UINT_MAX); size_t n = N > 0 ? N : 1; m_blob = new blob_t(sizeof(header_t) + n*sizeof(cons_t), alloc); @@ -46,8 +45,8 @@ void list::init(const eterm* items, size_t N, const Alloc& alloc) cons_t* hd = l_header->head; l_header->initialized = true; - l_header->alloc_size = (unsigned int)n; - l_header->size = (unsigned int)N; + l_header->alloc_size = n; + l_header->size = N; for(auto p = items, end = items+N; p != end; ++p, ++hd) { BOOST_ASSERT(p->initialized()); @@ -108,10 +107,11 @@ list::list(const char *buf, uintptr_t& idx, size_t size, const Alloc& a_a : base_t(a_alloc) { BOOST_ASSERT(idx <= INT_MAX); - int arity; - if (ei_decode_list_header(buf, (int*)&idx, &arity) < 0) + int n; + if (ei_decode_list_header(buf, (int*)&idx, &n) < 0) err_decode_exception("Error decoding list header", idx); + size_t arity = static_cast(n); // If this is an empty list - no allocation is needed if (arity == 0) { m_blob = empty_list(); @@ -174,7 +174,7 @@ list list::tail(size_t idx) const { const header_t* l_header = header(); const cons_t* p = l_header->head; - int len = (int)l_header->size - (int)idx - 1; + size_t len = l_header->size - idx - 1; if (len < 0) throw err_bad_argument("List too short"); for (size_t i=0; i <= idx; i++) diff --git a/include/eixx/marshal/pid.hpp b/include/eixx/marshal/pid.hpp index 8512705..c497891 100644 --- a/include/eixx/marshal/pid.hpp +++ b/include/eixx/marshal/pid.hpp @@ -54,11 +54,11 @@ class epid { uint32_t creation; atom node; - pid_blob(const atom& a_node, int a_id, int a_cre) + pid_blob(const atom& a_node, uint32_t a_id, uint32_t a_cre) : id(a_id), serial(0), creation(a_cre), node(a_node) {} - pid_blob(const atom& a_node, int a_id, int a_serial, int a_cre) + pid_blob(const atom& a_node, uint32_t a_id, uint32_t a_serial, uint32_t a_cre) : id(a_id), serial(a_serial), creation(a_cre), node(a_node) {} }; @@ -79,7 +79,7 @@ class epid { } // Must only be called from constructor! - void init(const atom& node, int id, int serial, uint32_t creation, const Alloc& alloc) + void init(const atom& node, uint32_t id, uint32_t serial, uint32_t creation, const Alloc& alloc) { m_blob = new blob(1, alloc); new (m_blob->data()) pid_blob(node, id, serial, creation); @@ -114,15 +114,15 @@ class epid { * @param a_alloc is the allocator to use. * @throw err_bad_argument if node is empty or greater than MAX_NODE_LENGTH **/ - epid(const char* node, int id, int serial, uint32_t creation, const Alloc& a_alloc = Alloc()) + epid(const char* node, uint32_t id, uint32_t serial, uint32_t creation, const Alloc& a_alloc = Alloc()) : epid(atom(node), id, serial, creation, a_alloc) {} - epid(const atom& node, int id, uint32_t creation, const Alloc& a_alloc = Alloc()) + epid(const atom& node, uint32_t id, uint32_t creation, const Alloc& a_alloc = Alloc()) : epid(node, id, 0, creation, a_alloc) {} - epid(const atom& node, int id, int serial, uint32_t creation, const Alloc& a_alloc = Alloc()) + epid(const atom& node, uint32_t id, uint32_t serial, uint32_t creation, const Alloc& a_alloc = Alloc()) { detail::check_node_length(node.size()); init(node, id, serial, creation, a_alloc); @@ -176,13 +176,13 @@ class epid { * Get the id number from the PID. * @return the id number from the PID. **/ - int id() const { return m_blob ? m_blob->data()->id : 0; } + uint32_t id() const { return m_blob ? m_blob->data()->id : 0; } /** * Get the serial number from the PID. * @return the serial number from the PID. **/ - int serial() const { return m_blob ? m_blob->data()->serial : 0; } + uint32_t serial() const { return m_blob ? m_blob->data()->serial : 0; } /** * Get the creation number from the PID. diff --git a/include/eixx/marshal/pid.hxx b/include/eixx/marshal/pid.hxx index 7c6c411..d90ae43 100644 --- a/include/eixx/marshal/pid.hxx +++ b/include/eixx/marshal/pid.hxx @@ -45,9 +45,11 @@ void epid::decode(const char *buf, uintptr_t& idx, [[maybe_unused]] size_ ) throw err_decode_exception("Error decoding pid's type", idx, tag); - int len = atom::get_len(s); - if (len < 0) - throw err_decode_exception("Error decoding pid node", idx, len); + const uint8_t atom_tag = get8(s); + long l = atom::get_len(s, atom_tag); + if (l < 0) + throw err_decode_exception("Error decoding pid's node", idx, l); + size_t len = static_cast(l); detail::check_node_length(len); atom l_node(s, len); @@ -63,7 +65,7 @@ void epid::decode(const char *buf, uintptr_t& idx, [[maybe_unused]] size_ init(l_node, l_id, l_ser, l_cre, alloc); - idx += s - s0; + idx += static_cast(s - s0); BOOST_ASSERT((size_t)idx <= size); } @@ -98,7 +100,7 @@ void epid::encode(char* buf, uintptr_t& idx, [[maybe_unused]] size_t size put8(s, l_cre & 0x03 /* 2 bits */); #endif - idx += s-s0; + idx += static_cast(s - s0); BOOST_ASSERT((size_t)idx <= size); } diff --git a/include/eixx/marshal/port.hpp b/include/eixx/marshal/port.hpp index b952141..744ebba 100644 --- a/include/eixx/marshal/port.hpp +++ b/include/eixx/marshal/port.hpp @@ -89,7 +89,7 @@ class port { * 2 bits will be used. * @throw err_bad_argument if node is empty or greater than MAX_NODE_LENGTH **/ - port(const char* node, const int id, const uint32_t creation, const Alloc& a_alloc = Alloc()) + port(const char* node, const uint64_t id, const uint32_t creation, const Alloc& a_alloc = Alloc()) { size_t n = strlen(node); detail::check_node_length(n); @@ -97,7 +97,7 @@ class port { init(l_node, id, creation, a_alloc); } - port(const atom& node, const int id, const uint32_t creation, const Alloc& a_alloc = Alloc()) + port(const atom& node, const uint64_t id, const uint32_t creation, const Alloc& a_alloc = Alloc()) { detail::check_node_length(node.size()); init(node, id, creation, a_alloc); diff --git a/include/eixx/marshal/port.hxx b/include/eixx/marshal/port.hxx index 2fff1da..f2fd41b 100644 --- a/include/eixx/marshal/port.hxx +++ b/include/eixx/marshal/port.hxx @@ -48,9 +48,11 @@ port::port(const char *buf, uintptr_t& idx, [[maybe_unused]] size_t size, ) throw err_decode_exception("Error decoding port's type", idx, tag); - int len = atom::get_len(s); - if (len < 0) - throw err_decode_exception("Error decoding port's node", idx, len); + const uint8_t atom_tag = get8(s); + long l = atom::get_len(s, atom_tag); + if (l < 0) + throw err_decode_exception("Error decoding port's node", idx, l); + size_t len = static_cast(l); detail::check_node_length(len); atom l_node(s, len); s += len; @@ -67,13 +69,13 @@ port::port(const char *buf, uintptr_t& idx, [[maybe_unused]] size_t size, #endif #ifdef ERL_NEW_PORT_EXT case ERL_NEW_PORT_EXT: - id = uint64_t(get32be(s)); + id = static_cast(get32be(s)); cre = get32be(s); break; #endif case ERL_PORT_EXT: - id = uint64_t(get32be(s) & 0x0fffffff); /* 28 bits */ - cre = get8(s) & 0x03; /* 2 bits */ + id = static_cast(get32be(s) & 0x0fffffff); /* 28 bits */ + cre = static_cast(get8(s) & 0x03); /* 2 bits */ break; default: @@ -81,7 +83,7 @@ port::port(const char *buf, uintptr_t& idx, [[maybe_unused]] size_t size, } init(l_node, id, cre, a_alloc); - idx += s - s0; + idx += static_cast(s - s0); BOOST_ASSERT((size_t)idx <= size); } @@ -125,7 +127,7 @@ void port::encode(char* buf, uintptr_t& idx, [[maybe_unused]] size_t size } #endif - idx += s-s0; + idx += static_cast(s - s0); BOOST_ASSERT((size_t)idx <= size); } diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index ac1f2e4..fef48dd 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -70,7 +70,7 @@ class ref { while(i < COUNT) ids[i++] = 0; } - template + template ref_blob(const atom& a_node, uint32_t (&a_ids)[N], uint32_t a_cre) : ref_blob(a_node, a_ids, N, a_cre) {} @@ -130,7 +130,7 @@ class ref { init(node, a_ids, n, creation, a_alloc); } - template + template ref(const atom& node, uint32_t (&ids)[N], uint32_t creation, const Alloc& a_alloc = Alloc()) : ref(node, ids, N, creation, a_alloc) @@ -238,7 +238,7 @@ class ref { } size_t encode_size() const { - return 1+2+(3+node().size()) + len()*4 + + return (size_t)1+2+(3+node().size()) + len()*4 + #ifdef ERL_NEWER_REFERENCE_EXT 4; #else @@ -264,7 +264,7 @@ namespace std { template ostream& operator<< (ostream& out, const eixx::marshal::ref& a) { out << "#Ref<" << a.node(); - for (int i=0, e=a.len(); i != e; ++i) + for (uint32_t i=0, e=a.len(); i != e; ++i) out << '.' << a.id(i); if (a.creation() > 0 && a.display_creation()) out << ',' << a.creation(); diff --git a/include/eixx/marshal/ref.hxx b/include/eixx/marshal/ref.hxx index 94c70c0..5215ea4 100644 --- a/include/eixx/marshal/ref.hxx +++ b/include/eixx/marshal/ref.hxx @@ -51,9 +51,11 @@ ref::ref(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t size, c if (count > COUNT) throw err_decode_exception("Error decoding ref's count", idx+1, count); - int len = atom::get_len(s); - if (len < 0) - throw err_decode_exception("Error decoding ref's atom", idx+3, len); + const uint8_t atom_tag = get8(s); + long l = atom::get_len(s, atom_tag); + if (l < 0) + throw err_decode_exception("Error decoding ref's node", idx, l); + size_t len = static_cast(l); detail::check_node_length(len); atom nd(s, len); s += len; @@ -69,14 +71,16 @@ ref::ref(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t size, c init(nd, vals, count, cre, a_alloc); - idx += s-s0; + idx += static_cast(s - s0); break; } #endif case ERL_REFERENCE_EXT: { - int len = atom::get_len(s); - if (len < 0) - throw err_decode_exception("Error decoding ref's atom", idx+3, len); + const uint8_t atom_tag = get8(s); + long l = atom::get_len(s, atom_tag); + if (l < 0) + throw err_decode_exception("Error decoding ref's node", idx, l); + size_t len = static_cast(l); detail::check_node_length(len); atom nd(s, len); s += len; @@ -86,7 +90,7 @@ ref::ref(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t size, c init(nd, &id, 1u, cre, a_alloc); - idx += s-s0; + idx += static_cast(s - s0); break; } default: @@ -130,7 +134,7 @@ void ref::encode(char* buf, uintptr_t& idx, [[maybe_unused]] size_t size) put32be(s, *p & 0x0003ffff /* 18 bits */); #endif - idx += s-s0; + idx += static_cast(s - s0); BOOST_ASSERT((size_t)idx <= size); } diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index 4764fc5..787487c 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -163,14 +163,14 @@ class string } /// Tests if this string is equal to the content of the binary buffer \a rhs. - template + template bool equal(const char (&rhs)[N]) const { int i = N > 0 && rhs[N-1] == '\0' ? -1 : 0; return strncmp(c_str(), rhs, size()+i) == 0; } /// Tests if this string is equal to the content of the binary buffer \a rhs. - template + template bool equal(const uint8_t (&rhs)[N]) const { int i = N > 0 && rhs[N-1] == '\0' ? -1 : 0; return strncmp(c_str(), (const char*)rhs, size()+i) == 0; @@ -216,7 +216,7 @@ string::string(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t s switch (tag) { case ERL_STRING_EXT: { - int len = get16be(s); + uint16_t len = get16be(s); if (len == 0) m_blob = NULL; else { @@ -233,15 +233,15 @@ string::string(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t s * but we decode as much as we can, exiting early if we run into a * non-character in the list. */ - int len = get32be(s); + uint32_t len = get32be(s); if (len == 0) m_blob = NULL; else { m_blob = new blob(len+1, a_alloc); - for (int i=0; idata()[i] = get8(s); + throw err_decode_exception("Error decoding string", static_cast(s - s0)+i); + m_blob->data()[i] = static_cast(get8(s)); } m_blob->data()[len] = '\0'; } @@ -254,7 +254,7 @@ string::string(const char* buf, uintptr_t& idx, [[maybe_unused]] size_t s default: throw err_decode_exception("Error decoding string's type", idx, tag); } - idx += s-s0; + idx += static_cast(s - s0); } } // namespace marshal @@ -274,7 +274,7 @@ namespace std { template bool operator== (const eixx::marshal::string& lhs, const std::string& rhs) { - return rhs == rhs.c_str(); + return lhs == rhs.c_str(); } template diff --git a/include/eixx/marshal/tuple.hpp b/include/eixx/marshal/tuple.hpp index f9765e6..094659c 100644 --- a/include/eixx/marshal/tuple.hpp +++ b/include/eixx/marshal/tuple.hpp @@ -55,7 +55,7 @@ class tuple { } size_t get_init_size() const { BOOST_ASSERT(m_blob); - return m_blob->data()[m_blob->size()-1].to_long()-1; + return static_cast(m_blob->data()[m_blob->size()-1].to_long()-1); } void release() { release(m_blob); m_blob = nullptr; } @@ -106,7 +106,7 @@ class tuple { a.m_blob = nullptr; } - template + template tuple(const eterm (&items)[N], const Alloc& alloc = Alloc()) : tuple(items, N, alloc) {} diff --git a/include/eixx/marshal/tuple.hxx b/include/eixx/marshal/tuple.hxx index 11580d6..a65b140 100644 --- a/include/eixx/marshal/tuple.hxx +++ b/include/eixx/marshal/tuple.hxx @@ -40,11 +40,13 @@ template tuple::tuple(const char* buf, uintptr_t& idx, size_t size, const Alloc& a_alloc) { BOOST_ASSERT(idx <= INT_MAX); - int arity; - if (ei_decode_tuple_header(buf, (int*)&idx, &arity) < 0) + int n; + if (ei_decode_tuple_header(buf, (int*)&idx, &n) < 0) err_decode_exception("Error decoding tuple header", idx); + + size_t arity = static_cast(n); m_blob = new blob, Alloc>(arity+1, a_alloc); - for (int i=0; i < arity; i++) { + for (size_t i=0; i < arity; i++) { new (&m_blob->data()[i]) eterm(buf, idx, size, a_alloc); } set_init_size(arity); diff --git a/include/eixx/marshal/visit_encode_size.hpp b/include/eixx/marshal/visit_encode_size.hpp index a9121e5..08a4fa8 100644 --- a/include/eixx/marshal/visit_encode_size.hpp +++ b/include/eixx/marshal/visit_encode_size.hpp @@ -40,7 +40,7 @@ struct visit_eterm_encode_size_calc size_t operator()(bool a) const { return 2 + (a ? 4 : 5); } size_t operator()(double ) const { return 9; } - size_t operator()(long a) const { int n = 0; ei_encode_longlong(NULL, &n, a); return n; } + size_t operator()(long a) const { int n = 0; ei_encode_longlong(NULL, &n, a); return static_cast(n); } template size_t operator()(const T& a) const { return a.encode_size(); } diff --git a/include/eixx/util/common.hpp b/include/eixx/util/common.hpp index 1c79499..57c229f 100644 --- a/include/eixx/util/common.hpp +++ b/include/eixx/util/common.hpp @@ -105,7 +105,7 @@ struct atomic { /// Return the index of a_string in the a_list using a_default index if /// a_string is not found in the list. -template +template int find_index(const char* (&a_list)[N], const char* a_string, int a_default=-1) { for (int i=0; i < N; i++) if (strcmp(a_string, a_list[i]) == 0) diff --git a/include/eixx/util/hashtable.hpp b/include/eixx/util/hashtable.hpp index 6ff9cbd..2360306 100644 --- a/include/eixx/util/hashtable.hpp +++ b/include/eixx/util/hashtable.hpp @@ -99,7 +99,7 @@ struct hsieh_hash_fun { hash ^= hash << 25; hash += hash >> 6; - return hash; + return static_cast(hash); } }; diff --git a/include/eixx/util/string_util.hpp b/include/eixx/util/string_util.hpp index 5d32f22..7a25ed1 100644 --- a/include/eixx/util/string_util.hpp +++ b/include/eixx/util/string_util.hpp @@ -95,7 +95,7 @@ inline const char* fast_atoi(const char* a_str, const char* a_end, T& res) { namespace std { - template + template std::string to_string(const uint8_t (&s)[N]) { return std::string((const char*)s, N); } } From 8d0c247b0c6207d89fdf001489a0deea4fcee613 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Sat, 28 Aug 2021 03:41:37 +0800 Subject: [PATCH 172/185] Increase connection and atom system limits --- include/eixx/connect/basic_otp_node.hxx | 13 ++++-- include/eixx/marshal/atom.hpp | 14 ++++--- include/eixx/util/atom_table.hpp | 55 ++++++++++++++----------- 3 files changed, 48 insertions(+), 34 deletions(-) diff --git a/include/eixx/connect/basic_otp_node.hxx b/include/eixx/connect/basic_otp_node.hxx index 00acc1c..2e1b390 100644 --- a/include/eixx/connect/basic_otp_node.hxx +++ b/include/eixx/connect/basic_otp_node.hxx @@ -45,13 +45,20 @@ namespace { //----------------------------------------------------------------------------- template class basic_otp_node::atom_con_hash_fun { + static constexpr size_t s_default_max_ports = 16*1024; + conn_hash_map& map; static size_t init_default_hash_size() { + // See: https://erlang.org/doc/efficiency_guide/advanced.html#ports const char* p = getenv("EI_MAX_NODE_CONNECTIONS"); - int n = (p && p[0]) ? atoi(p) : 1024; - if (n < 0 || n >= 64*1024) n = 1024; - return static_cast(n); + size_t n = 0; + if (p) { + std::stringstream ss(p); + ss >> n; + } + // if (n > 64*1024) n = 64*1024; + return n > 0 ? n : s_default_max_ports; } public: static size_t get_default_hash_size() { diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 596b7e1..2b9cd78 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -65,9 +65,9 @@ namespace detail { */ class atom { - int m_index; + uint32_t m_index; - atom(int idx) : m_index(idx) { assert(idx >= 0); } + atom(uint32_t idx) : m_index(idx) { assert(idx >= 0); } public: inline static util::atom_table& atom_table() { static util::atom_table s_atom_table; @@ -106,7 +106,7 @@ class atom /// is true, then an empty atom is returned. static atom create(const std::string& s, bool existing) { auto idx = atom_table().try_lookup(s); - return idx > 0 && existing ? atom(idx) : atom(); + return idx <= UINT32_MAX && existing ? atom((uint32_t)idx) : atom(); } /// @copydoc atom::create static atom create(const char* s, bool existing) { @@ -143,8 +143,10 @@ class atom m_index = atom_table().lookup(s); return; } - m_index = atom_table().try_lookup(s); - if (m_index <= 0) + auto idx = atom_table().try_lookup(s); + if (idx <= UINT32_MAX) + m_index = (uint32_t)idx; + else throw err_atom_not_found(s); } @@ -189,7 +191,7 @@ class atom bool empty() const { return m_index == 0; } /// Get atom's index in the atom table. - int index() const { return m_index; } + uint32_t index() const { return m_index; } void operator= (const atom& s) { m_index = s.m_index; } void operator= (const std::string& s) { m_index = atom_table().lookup(s); } diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index d8320e9..b080120 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -66,21 +66,28 @@ namespace util { typename Mutex = eid::mutex > class basic_atom_table : private detail::hsieh_hash_fun { - static const int s_default_max_atoms = 1024*1024; + static constexpr size_t s_default_max_atoms = 1024*1024; - int find_value(size_t bucket, const char* a_atom) { + size_t find_value(size_t bucket, const char* a_atom) { typename HashMap::const_local_iterator lit = m_index.begin(bucket), lend = m_index.end(bucket); while(lit != lend && strcmp(a_atom, lit->first) != 0) ++lit; - return lit == lend ? -1 : lit->second; + return lit == lend ? (size_t)-1 : lit->second; } public: /// Returns the default atom table maximum size. The value can be /// changed by setting the EI_ATOM_TABLE_SIZE environment variable. static size_t default_size() { + // See: https://erlang.org/doc/efficiency_guide/advanced.html#atoms const char* p = getenv("EI_ATOM_TABLE_SIZE"); - int n = p ? atoi(p) : s_default_max_atoms; - return n > 0 && n < 1024*1024*100 ? n : s_default_max_atoms; + size_t n = 0; + if (p) { + std::stringstream ss(p); + ss >> n; + } + // Hash function only supports up to UINT32_MAX + if (n > UINT32_MAX+1) n = UINT32_MAX+1; + return n > 0 ? n : s_default_max_atoms; } /// Returns the maximum number of atoms that can be stored in the atom table. @@ -103,10 +110,10 @@ namespace util { } /// Lookup an atom in the atom table by index. - const String& get(int n) const { return (*this)[n]; } + const String& get(size_t n) const { return (*this)[n]; } /// Lookup an atom in the atom table by index. - const String& operator[] (int n) const { + const String& operator[] (size_t n) const { BOOST_ASSERT((size_t)n < m_atoms.size()); return m_atoms[n]; } @@ -114,17 +121,16 @@ namespace util { /// Try to lookup an atom in the atom table /// @return -1 if the atom by name is not found, -2 if the atom is invalid, /// or a value >= 0, if an existing atom is found. - int try_lookup(const char* a_name, size_t n) { return try_lookup(String(a_name, n)); } - int try_lookup(const char* a_name) { return try_lookup(String(a_name)); } - int try_lookup(const String& a_name) + size_t try_lookup(const char* a_name, size_t n) { return try_lookup(String(a_name, n)); } + size_t try_lookup(const char* a_name) { return try_lookup(String(a_name)); } + size_t try_lookup(const String& a_name) { if (a_name.size() == 0) return 0; if (a_name.size() > MAXATOMLEN_UTF8 || utf8_length(a_name) > MAXATOMLEN) - return -2; + return (size_t)-2; size_t bucket = m_index.bucket(a_name.c_str()); - int n = find_value(bucket, a_name.c_str()); - return n > 0 ? n : -1; + return find_value(bucket, a_name.c_str()); } /// Lookup an atom in the atom table by name. If the atom is not @@ -132,29 +138,28 @@ namespace util { /// atom in the atom table. /// @throw std::runtime_error if atom table is full. /// @throw err_bad_argument if atom size is longer than MAXATOMLEN - int lookup(const char* a_name, size_t n) { return lookup(String(a_name, n)); } - int lookup(const char* a_name) { return lookup(String(a_name)); } - int lookup(const String& a_name) + uint32_t lookup(const char* a_name, size_t n) { return lookup(String(a_name, n)); } + uint32_t lookup(const char* a_name) { return lookup(String(a_name)); } + uint32_t lookup(const String& a_name) { - int n = try_lookup(a_name); - if (n >= 0) return n; - if (n == -2) throw err_bad_argument("Atom size is too long!"); + size_t n = try_lookup(a_name); + if (n <= UINT32_MAX) return (uint32_t)n; + if (n == (size_t)-2) throw err_bad_argument("Atom size is too long!"); lock_guard guard(m_lock); if (!std::is_same::value) { size_t bucket = m_index.bucket(a_name.c_str()); n = find_value(bucket, a_name.c_str()); - if (n >= 0) - return n; + if (n <= UINT32_MAX) + return (uint32_t)n; } - size_t sz = m_atoms.size(); - if (sz > INT_MAX || sz == m_atoms.capacity()) + n = m_atoms.size(); + if (n > UINT32_MAX || (n+1) == m_atoms.capacity()) throw std::runtime_error("Atom hash table is full!"); - n = (int)sz; m_atoms.push_back(a_name); m_index[m_atoms.back().c_str()] = n; - return n; + return (uint32_t)n; } private: Vector m_atoms; From 8c4594d35686258145dd67329aea95bae2c5f69e Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Sat, 28 Aug 2021 03:55:23 +0800 Subject: [PATCH 173/185] fix warnings not caught by gcc (only by clang) --- include/eixx/marshal/eterm_match.hpp | 2 +- include/eixx/marshal/list.hpp | 2 +- include/eixx/marshal/list.hxx | 12 +++++------- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/include/eixx/marshal/eterm_match.hpp b/include/eixx/marshal/eterm_match.hpp index 8b0097d..eeb6202 100644 --- a/include/eixx/marshal/eterm_match.hpp +++ b/include/eixx/marshal/eterm_match.hpp @@ -228,7 +228,7 @@ class eterm_pattern_action { explicit eterm_pattern_action(const eterm& a_pattern) : m_pattern(a_pattern), m_opaque(0) { - auto fun = [](auto& pattern, auto& vars, long opaque) { return true; }; + auto fun = [](auto& /*pattern*/, auto& /*vars*/, long /*opaque*/) { return true; }; m_fun = fun; } diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 1c84251..210bce5 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -163,7 +163,7 @@ class list : protected alloc_base, Alloc> { a.m_blob = nullptr; } - explicit list(const cons_t* a_head, int a_len = -1, const Alloc& alloc = Alloc()); + explicit list(const cons_t* a_head, size_t a_len = 0, const Alloc& alloc = Alloc()); template list(const eterm (&items)[N], const Alloc& alloc = Alloc()) diff --git a/include/eixx/marshal/list.hxx b/include/eixx/marshal/list.hxx index 327c056..d0ba0d0 100644 --- a/include/eixx/marshal/list.hxx +++ b/include/eixx/marshal/list.hxx @@ -63,20 +63,18 @@ void list::init(const eterm* items, size_t N, const Alloc& alloc) } template -list::list(const cons_t* a_head, int a_len, const Alloc& alloc) +list::list(const cons_t* a_head, size_t a_len, const Alloc& alloc) : base_t(alloc) { - unsigned int alloc_size; + size_t alloc_size; - if (a_len >= 0) { + if (a_len > 0) { alloc_size = a_len; - } else if (a_len == -1) { - a_len = 0; + } else if (a_len == 0) { for (const cons_t* p = a_head; p; p = p->next) a_len++; alloc_size = a_len; - } else - throw err_bad_argument("List of negative length!"); + } // If this is an empty list - no allocation is needed if (alloc_size == 0) { From f3c3e69b6b3c543a2cb62b63a5144427f8e02cac Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Mon, 30 Aug 2021 19:35:35 +0800 Subject: [PATCH 174/185] backwards compatible with boost <=1.75 --- include/eixx/connect/transport_otp_connection_tcp.hpp | 1 - include/eixx/connect/transport_otp_connection_tcp.hxx | 6 +++++- include/eixx/marshal/atom.hpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/eixx/connect/transport_otp_connection_tcp.hpp b/include/eixx/connect/transport_otp_connection_tcp.hpp index 305a153..05e0b79 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hpp +++ b/include/eixx/connect/transport_otp_connection_tcp.hpp @@ -48,7 +48,6 @@ class tcp_connection { public: typedef connection base_t; - typedef boost::asio::ip::port_type port_t; tcp_connection(boost::asio::io_service& a_svc, Handler* a_h, const Alloc& a_alloc) : connection(TCP, a_svc, a_h, a_alloc) diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index 4286980..fd93410 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -273,7 +273,11 @@ void tcp_connection::handle_epmd_read_body( BOOST_ASSERT(got_bytes >= 10); const char* l_epmd_rd = m_buf_epmd + 2; - port_t port = get16be(l_epmd_rd); +#if BOOST_VERSION >= 107600 + boost::asio::ip::port_type port = get16be(l_epmd_rd); +#else + uint16_t port = get16be(l_epmd_rd); +#endif int ntype = get8(l_epmd_rd); int proto = get8(l_epmd_rd); uint16_t dist_high = get16be(l_epmd_rd); diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index 2b9cd78..e1fe9c8 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -67,7 +67,7 @@ class atom { uint32_t m_index; - atom(uint32_t idx) : m_index(idx) { assert(idx >= 0); } + atom(uint32_t idx) : m_index(idx) {} public: inline static util::atom_table& atom_table() { static util::atom_table s_atom_table; From ca78984a8a470b69a0282ade1381a4a19d923d0d Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Mon, 30 Aug 2021 23:42:00 +0800 Subject: [PATCH 175/185] reduce warnings in tests --- include/eixx/marshal/eterm.hpp | 1 + include/eixx/marshal/list.hpp | 10 +++++++++ include/eixx/marshal/list.hxx | 2 +- include/eixx/marshal/ref.hpp | 11 ++++++---- include/eixx/marshal/string.hpp | 6 ++++-- test/test_async_queue.cpp | 22 +++++++++---------- test/test_eterm.cpp | 22 +++++++++---------- test/test_eterm_encode.cpp | 38 ++++++++++++++++----------------- test/test_eterm_match.cpp | 4 ++-- test/test_eterm_pool.cpp | 4 ++-- test/test_eterm_refc.cpp | 10 ++++----- 11 files changed, 73 insertions(+), 57 deletions(-) diff --git a/include/eixx/marshal/eterm.hpp b/include/eixx/marshal/eterm.hpp index 28db90a..b3ba28a 100644 --- a/include/eixx/marshal/eterm.hpp +++ b/include/eixx/marshal/eterm.hpp @@ -448,6 +448,7 @@ class eterm { std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 210bce5..6d3e151 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -135,6 +135,16 @@ class list : protected alloc_base, Alloc> { /// Construct an NIL list (initialized list with no elements) explicit list(std::nullptr_t) : m_blob(empty_list()) {} + /// Construct a list with a given estimated size. + /// + /// When a_estimated_size is 0, an empty initialized list is created. Otherwise, + /// the list is not initialized. + explicit list(int a_estimated_size, const Alloc& alloc = Alloc()) { + if (a_estimated_size < 0) + throw err_bad_argument("List too short"); + list((size_t)a_estimated_size, alloc); + } + /// Construct a list with a given estimated size. /// /// When a_estimated_size is 0, an empty initialized list is created. Otherwise, diff --git a/include/eixx/marshal/list.hxx b/include/eixx/marshal/list.hxx index d0ba0d0..7d09030 100644 --- a/include/eixx/marshal/list.hxx +++ b/include/eixx/marshal/list.hxx @@ -173,7 +173,7 @@ list list::tail(size_t idx) const const header_t* l_header = header(); const cons_t* p = l_header->head; size_t len = l_header->size - idx - 1; - if (len < 0) + if (idx >= l_header->size) throw err_bad_argument("List too short"); for (size_t i=0; i <= idx; i++) p = p->next; diff --git a/include/eixx/marshal/ref.hpp b/include/eixx/marshal/ref.hpp index fef48dd..074a806 100644 --- a/include/eixx/marshal/ref.hpp +++ b/include/eixx/marshal/ref.hpp @@ -124,7 +124,7 @@ class ref { * 2 bits will be used. * @throw err_bad_argument if node is empty or greater than MAX_NODE_LENGTH */ - ref(const atom& node, const uint32_t* a_ids, size_t n, uint32_t creation, + ref(const atom& node, const uint32_t* a_ids, uint16_t n, uint32_t creation, const Alloc& a_alloc = Alloc()) { init(node, a_ids, n, creation, a_alloc); @@ -144,10 +144,13 @@ class ref { {} // For internal use - ref(const atom& node, std::initializer_list a_ids, uint8_t creation, + ref(const atom& node, std::initializer_list a_ids, uint32_t creation, const Alloc& a_alloc = Alloc()) - : ref(node, &*a_ids.begin(), a_ids.size(), creation, a_alloc) - {} + : ref(node, &*a_ids.begin(), (uint16_t)a_ids.size(), creation, a_alloc) + { + if (a_ids.size() > UINT16_MAX) + throw err_bad_argument("Ref too long"); + } /** * Construct the object by decoding it from a binary diff --git a/include/eixx/marshal/string.hpp b/include/eixx/marshal/string.hpp index 787487c..c325ffb 100644 --- a/include/eixx/marshal/string.hpp +++ b/include/eixx/marshal/string.hpp @@ -172,8 +172,10 @@ class string /// Tests if this string is equal to the content of the binary buffer \a rhs. template bool equal(const uint8_t (&rhs)[N]) const { - int i = N > 0 && rhs[N-1] == '\0' ? -1 : 0; - return strncmp(c_str(), (const char*)rhs, size()+i) == 0; + size_t sz = size(); + if (sz > 0 && N > 0 && rhs[N-1] == '\0') + sz -= 1; + return strncmp(c_str(), (const char*)rhs, sz) == 0; } /** Size of binary buffer needed to hold the encoded string. */ diff --git a/test/test_async_queue.cpp b/test/test_async_queue.cpp index fc3ca21..0544a5c 100644 --- a/test/test_async_queue.cpp +++ b/test/test_async_queue.cpp @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE( test_async_queue ) std::shared_ptr> q(new async_queue(io)); bool res = q->async_dequeue( - [](int& a, const boost::system::error_code& ec) { + [](int& /*a*/, const boost::system::error_code& /*ec*/) { throw std::exception(); // This handler is never called return false; }, @@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE( test_async_queue ) for (int j = 10; j < 13; j++) { BOOST_REQUIRE(q->async_dequeue( - [j](int& a, const boost::system::error_code& ec) { + [j](int& a, const boost::system::error_code& /*ec*/) { BOOST_REQUIRE_EQUAL(j, a); return true; }, @@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE( test_async_queue ) b = 15; bool r = q->async_dequeue( - [](int& a, const boost::system::error_code& ec) { + [](int& a, const boost::system::error_code& /*ec*/) { BOOST_REQUIRE_EQUAL(b++, a); n++; return true; @@ -102,15 +102,15 @@ namespace { std::atomic done (false); } -void producer(async_queue& q, int i) +void producer(async_queue& q, int id) { - for (int i = 0; i != iterations; ++i) { + for (int idx = 0; idx != iterations; ++idx) { int value = ++producer_count; while (!q.enqueue(value)); } if (eixx::verboseness::level() >= eixx::connect::VERBOSE_DEBUG) - std::cout << "Producer thread " << i << " done" << std::endl; + std::cout << "Producer thread " << id << " done" << std::endl; done = ++done_producer_count == producer_thread_count; } @@ -123,13 +123,13 @@ BOOST_AUTO_TEST_CASE( test_async_queue_concurrent ) boost::thread_group producer_threads; - for (int i = 0; i < producer_thread_count; ++i) + for (int idx = 0; idx < producer_thread_count; ++idx) producer_threads.create_thread( - [&q, i] () { producer(*q, i+1); } + [&q, idx] () { producer(*q, idx+1); } ); while(q->async_dequeue( - [] (int& v, const boost::system::error_code& ec) { + [] (int& /*v*/, const boost::system::error_code& ec) { if (!ec) ++consumer_count; return !(done && consumer_count >= producer_count); @@ -150,7 +150,7 @@ BOOST_AUTO_TEST_CASE( test_async_queue_concurrent ) bool abort = false; auto r = q->async_dequeue( - [&abort] (int& v, const boost::system::error_code& ec) { return !abort; }, + [&abort] (int& /*v*/, const boost::system::error_code& /*ec*/) { return !abort; }, std::chrono::milliseconds(8000), -1); @@ -158,7 +158,7 @@ BOOST_AUTO_TEST_CASE( test_async_queue_concurrent ) boost::asio::system_timer t(io); t.expires_from_now(std::chrono::milliseconds(1)); - t.async_wait([&q, &abort](const boost::system::error_code& e) { + t.async_wait([&q, &abort](const boost::system::error_code& /*e*/) { q->cancel(); abort = true; if (eixx::verboseness::level() >= eixx::connect::VERBOSE_DEBUG) diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 4e352ea..02f2311 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE( test_atomable ) util::atom_table t(10); BOOST_CHECK_EQUAL(0, t.lookup(std::string())); BOOST_CHECK_EQUAL(0, t.lookup("")); - int n = t.lookup("abc"); + uint32_t n = t.lookup("abc"); BOOST_CHECK(0 < n); BOOST_CHECK(0 < t.lookup("aaaaa")); BOOST_CHECK_EQUAL(n, t.lookup("abc")); @@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE( test_atom ) { const uint8_t buf[] = {ERL_ATOM_UTF8_EXT,0,3,97,98,99}; - int i = 0; + uintptr_t i = 0; atom atom((const char*)buf, i, sizeof(buf)); BOOST_CHECK_EQUAL(6, i); BOOST_CHECK_EQUAL("abc", atom); @@ -149,14 +149,14 @@ BOOST_AUTO_TEST_CASE( test_bool ) { const uint8_t buf[] = {ERL_ATOM_UTF8_EXT,0,4,116,114,117,101}; - int i = 0; + uintptr_t i = 0; eterm t((const char*)buf, i, sizeof(buf), alloc); BOOST_CHECK_EQUAL(true, t.to_bool()); BOOST_CHECK_EQUAL(std::string("true"), t.to_string()); } { const uint8_t buf[] = {ERL_ATOM_UTF8_EXT,0,5,102,97,108,115,101}; - int i = 0; + uintptr_t i = 0; eterm t((const char*)buf, i, sizeof(buf), alloc); BOOST_CHECK_EQUAL(sizeof(buf), (size_t)i); BOOST_CHECK_EQUAL(false, t.to_bool()); @@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE( test_binary ) { const uint8_t buf[] = {ERL_BINARY_EXT,0,0,0,3,97,98,99}; - int i = 0; + uintptr_t i = 0; binary term1((const char*)buf, i, sizeof(buf), alloc); i = 0; binary term2((const char*)buf, i, sizeof(buf), alloc); @@ -344,14 +344,14 @@ BOOST_AUTO_TEST_CASE( test_double ) const uint8_t buf[] = {ERL_FLOAT_EXT,49,46,48,48,48,48,48,48,48, 48,48,48,48,48,48,48,48,48,48,48,48,48,101, 43,48,48,0,0,0,0,0}; - int i = 0; + uintptr_t i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); BOOST_CHECK_EQUAL(32, i); BOOST_CHECK_EQUAL(1.0, term.to_double()); } { const uint8_t buf[] = {NEW_FLOAT_EXT,63,240,0,0,0,0,0,0}; - int i = 0; + uintptr_t i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); BOOST_CHECK_EQUAL(9, i); BOOST_CHECK_EQUAL(1.0, term.to_double()); @@ -385,7 +385,7 @@ BOOST_AUTO_TEST_CASE( test_long ) } { const uint8_t buf[] = {ERL_INTEGER_EXT,7,91,205,21}; - int i = 0; + uintptr_t i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); BOOST_CHECK_EQUAL(5, i); BOOST_CHECK_EQUAL (123456789, term.to_long()); @@ -393,7 +393,7 @@ BOOST_AUTO_TEST_CASE( test_long ) } { const uint8_t buf[] = {ERL_SMALL_BIG_EXT,4,1,210,2,150,73}; - int i = 0; + uintptr_t i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); BOOST_CHECK_EQUAL(7, i); BOOST_CHECK_EQUAL (-1234567890, term.to_long()); @@ -419,7 +419,7 @@ BOOST_AUTO_TEST_CASE( test_string ) { const uint8_t buf[] = {ERL_STRING_EXT,0,3,97,98,99}; - int i = 0; + uintptr_t i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); BOOST_CHECK_EQUAL(6, i); BOOST_CHECK_EQUAL("abc", term.to_str()); @@ -490,7 +490,7 @@ BOOST_AUTO_TEST_CASE( test_map ) { // #{1=>2, a => 3} const uint8_t buf[] = {ERL_MAP_EXT,0,0,0,2,97,1,97,2,100,0,1,97,97,3}; - int i = 0; + uintptr_t i = 0; eterm term((const char*)buf, i, sizeof(buf), alloc); BOOST_CHECK_EQUAL(15, i); BOOST_CHECK(term.is_map()); diff --git a/test/test_eterm_encode.cpp b/test/test_eterm_encode.cpp index 2d6e07a..0d79d14 100644 --- a/test/test_eterm_encode.cpp +++ b/test/test_eterm_encode.cpp @@ -31,7 +31,7 @@ BOOST_AUTO_TEST_CASE( test_encode_string ) string s(t.encode(0)); const uint8_t expect[] = {131,107,0,3,97,98,99}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte string t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(3ul, t1.size()); eterm et(t1); @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE( test_encode_atom ) string s(a.encode(0)); const uint8_t expect[] = {131,119,0,3,97,98,99}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte atom t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(3ul, t1.size()); BOOST_CHECK_EQUAL("abc", eterm(t1).to_string()); @@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE( test_encode_double ) string s(t.encode(0)); const uint8_t expect[] = {131,70,64,200,28,214,230,49,248,161}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(d, t1.to_double()); } @@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE( test_encode_emptylist ) string s(t.encode(0)); const uint8_t expect[] = {131,106}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(LIST, t1.type()); BOOST_CHECK_EQUAL(0ul, t1.to_list().length()); @@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE( test_encode_list ) const uint8_t expect[] = {131,108,0,0,0,4,ERL_ATOM_UTF8_EXT,0,3,97,98,99, 107,0,2,101,102,97,1,107,0,2,103,104,106}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte list t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(4ul, t1.length()); std::string str(eterm(t1).to_string()); @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE( test_encode_long ) string s(t.encode(0)); const uint8_t expect[] = {131,97,123}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(d, t1.to_long()); } @@ -137,7 +137,7 @@ BOOST_AUTO_TEST_CASE( test_encode_long ) string s(t.encode(0)); const uint8_t expect[] = {131,98,0,0,48,57}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(d, t1.to_long()); } @@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE( test_encode_long ) const uint8_t expect[] = {131,110,4,0,0x78,0x56,0x34,0x12}; #endif // EIXX_SIZEOF_LONG >= 8 BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(d, t1.to_long()); } @@ -171,14 +171,14 @@ BOOST_AUTO_TEST_CASE( test_encode_pid ) const uint8_t expect[] = {131,88,118,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0,0,0,2,0,0,0,0}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte eterm pid(epid((const char*)expect, idx, sizeof(expect))); BOOST_CHECK_EQUAL(eterm(pid), t); } { const uint8_t expect[] = {131,88,118,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0,0,0,2,0,0,0,3}; - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte epid decode_pid((const char*)expect, idx, sizeof(expect)); epid expect_pid("test@host", 1, 2, 3); BOOST_CHECK_EQUAL(expect_pid, decode_pid); @@ -194,7 +194,7 @@ BOOST_AUTO_TEST_CASE( test_encode_port ) const uint8_t expect[] = {131,102,ERL_ATOM_UTF8_EXT,0,9,116,101,115,116,64,104,111,115,116,0,0,0,1,0}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(t1, t); } @@ -209,17 +209,17 @@ BOOST_AUTO_TEST_CASE( test_encode_ref ) const uint8_t expect[] = {131,90,0,3,100,0,9,116,101,115,116,64,104,111,115,116,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte ref t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(eterm(t1), t); { - ref t(atom("abc@fc12"), 993, 0, 0, 2); + ref t2(atom("abc@fc12"), 993, 0, 0, 2); //std::cout << string(eterm(t).encode(0)).to_binary_string() << std::endl; - const uint8_t expect[] = + const uint8_t expect2[] = {131,90,0,3,118,0,8,97,98,99,64,102,99,49,50,0,0,0,2,0,0,3,225,0,0,0,0,0,0,0,0}; - int idx = 1; // skipping the magic byte - ref t1((const char*)expect, idx, sizeof(expect)); - BOOST_CHECK_EQUAL(t1, t); + uintptr_t idx2 = 1; // skipping the magic byte + ref t3((const char*)expect2, idx2, sizeof(expect2)); + BOOST_CHECK_EQUAL(t2, t3); } } @@ -246,7 +246,7 @@ BOOST_AUTO_TEST_CASE( test_encode_tuple ) 104,4,ERL_ATOM_UTF8_EXT,0,1,97,107,0,2,120,120,70,64,94,198,102, 102,102,102,102,97,5,107,0,2,103,104}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte tuple t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(5ul, t1.size()); BOOST_CHECK_EQUAL("{abc,\"ef\",1,{a,\"xx\",123.1,5},\"gh\"}", eterm(t1).to_string()); @@ -262,7 +262,7 @@ BOOST_AUTO_TEST_CASE( test_encode_trace ) const uint8_t expect[] = {131,104,5,97,1,97,2,97,3,88,118,0,8,97,98,99,64,102,99,49,50,0,0,0,96,0,0,0,0,0,0,0,3,97,4}; BOOST_CHECK(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte trace t1((const char*)expect, idx, sizeof(expect)); BOOST_CHECK_EQUAL(5ul, t1.size()); BOOST_CHECK_EQUAL(1, t1.flags()); diff --git a/test/test_eterm_match.cpp b/test/test_eterm_match.cpp index 6e911b9..dde860a 100644 --- a/test/test_eterm_match.cpp +++ b/test/test_eterm_match.cpp @@ -76,13 +76,13 @@ namespace { int match[10]; cb_t() { bzero(match, sizeof(match)); } - bool operator() (const eterm& a_pattern, + bool operator() (const eterm& /*a_pattern*/, const varbind& a_varbind, long a_opaque) { const eterm* n_var = a_varbind.find("N"); if (n_var && n_var->type() == LONG) { - int n = n_var->to_long(); + long n = n_var->to_long(); switch (a_opaque) { case 1: match[0]++; diff --git a/test/test_eterm_pool.cpp b/test/test_eterm_pool.cpp index 02fa504..97601a1 100644 --- a/test/test_eterm_pool.cpp +++ b/test/test_eterm_pool.cpp @@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE( test_encode_double_t ) string s(t.encode(0)); const uint8_t expect[] = {131,70,64,200,28,214,230,49,248,161}; BOOST_REQUIRE(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); BOOST_REQUIRE_EQUAL(d, t1.to_double()); } @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE( test_encode_long_t ) string s(t.encode(0)); const uint8_t expect[] = {131,97,123}; BOOST_REQUIRE(s.equal(expect)); - int idx = 1; // skipping the magic byte + uintptr_t idx = 1; // skipping the magic byte eterm t1((const char*)expect, idx, sizeof(expect)); BOOST_REQUIRE_EQUAL(d, t1.to_long()); } diff --git a/test/test_eterm_refc.cpp b/test/test_eterm_refc.cpp index cdf7786..d4f9ecd 100644 --- a/test/test_eterm_refc.cpp +++ b/test/test_eterm_refc.cpp @@ -31,7 +31,7 @@ static int g_alloc_count; template struct counted_alloc : public std::allocator { counted_alloc() {} - counted_alloc(const counted_alloc& a) {} + counted_alloc(const counted_alloc& /*a*/) {} template counted_alloc(const _T&) {} @@ -55,7 +55,7 @@ struct counted_alloc : public std::allocator { return static_cast(::operator new(n * sizeof(T))); } - void deallocate(pointer p, size_t sz) { + void deallocate(pointer p, size_t /*sz*/) { --g_alloc_count; ::operator delete(p); } @@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE( test_refc_format ) BOOST_CHECK_EQUAL(2+(6*2), g_alloc_count); for (int j=0; j <= 10; j++) - eterm term = eterm::format(alloc, + eterm term2 = eterm::format(alloc, "{~i, [{~s, ~i}, {~a, ~i}], {~f, ~i}, ~a}", 1, "ab", 2, "xx", 3, 2.1, 10, "abc"); } @@ -101,10 +101,10 @@ BOOST_AUTO_TEST_CASE( test_refc_pool_format ) BOOST_CHECK_EQUAL(LIST, term.type()); for (int j=0; j <= 10; j++) { - eterm term = eterm::format(alloc, + eterm term2 = eterm::format(alloc, "{~i, [{~s, ~i}, {~a, ~i}], {~f, ~i}, ~a}", 1, "ab", 2, "xx", 3, 2.1, 10, "abc"); - BOOST_CHECK_EQUAL(TUPLE, term.type()); + BOOST_CHECK_EQUAL(TUPLE, term2.type()); } } } From cbf33d9bc453e8ce454b0e41771094f928ed47a4 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Mon, 30 Aug 2021 23:43:39 +0800 Subject: [PATCH 176/185] compile tests on non-linux --- CMakeLists.txt | 5 +---- test/CMakeLists.txt | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7630a71..a1dcd09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,10 +179,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.in" #------------------------------------------------------------------------------- add_subdirectory(${CMAKE_SOURCE_DIR}/src) -if(CMAKE_SYSTEM_NAME STREQUAL Linux OR - CMAKE_SYSTEM_NAME STREQUAL Android) - add_subdirectory(${CMAKE_SOURCE_DIR}/test) -endif() +add_subdirectory(${CMAKE_SOURCE_DIR}/test) #=============================================================================== # Installation diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d0942f9..a0fed64 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,13 +28,16 @@ target_link_libraries( ${Boost_LIBRARIES} ) -add_executable(test-perf test_perf.cpp) -target_link_libraries( - test-perf - eixx - ${Erlang_EI_LIBRARIES} - ${Boost_LIBRARIES} -) +if(CMAKE_SYSTEM_NAME STREQUAL Linux OR + CMAKE_SYSTEM_NAME STREQUAL Android) + add_executable(test-perf test_perf.cpp) + target_link_libraries( + test-perf + eixx + ${Erlang_EI_LIBRARIES} + ${Boost_LIBRARIES} + ) +endif() if (NOT EIXX_MARSHAL_ONLY) add_executable(test-connect test_async_queue.cpp) @@ -48,13 +51,31 @@ if (NOT EIXX_MARSHAL_ONLY) install( TARGETS - test-eterm test-perf + test-eterm RUNTIME DESTINATION test ) + + if(CMAKE_SYSTEM_NAME STREQUAL Linux OR + CMAKE_SYSTEM_NAME STREQUAL Android) + install( + TARGETS + test-perf + RUNTIME DESTINATION test + ) + endif() endif() install( TARGETS - test-eterm test-perf + test-eterm RUNTIME DESTINATION test ) + +if(CMAKE_SYSTEM_NAME STREQUAL Linux OR + CMAKE_SYSTEM_NAME STREQUAL Android) + install( + TARGETS + test-perf + RUNTIME DESTINATION test + ) +endif() From 464824c07f7ddc7517274776caf580349a21c113 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 31 Aug 2021 19:39:11 -0400 Subject: [PATCH 177/185] Fix warnings, and creation of new pid/ref --- include/eixx/connect/basic_otp_node.hpp | 10 ++++++--- include/eixx/connect/basic_otp_node.hxx | 29 +++++++++++++++++++------ include/eixx/util/hashtable.hpp | 4 ++-- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/include/eixx/connect/basic_otp_node.hpp b/include/eixx/connect/basic_otp_node.hpp index 2f196c8..1af3220 100644 --- a/include/eixx/connect/basic_otp_node.hpp +++ b/include/eixx/connect/basic_otp_node.hpp @@ -83,10 +83,14 @@ class basic_otp_node: public basic_otp_node_local { Mutex m_lock; uint32_t m_creation; - std::atomic_int m_pid_count; - std::atomic_int m_port_count; + std::atomic_uint m_pid_count; + std::atomic_uint m_port_count; std::atomic_uint_fast64_t m_refid0; - std::atomic_int m_refid1; + #ifdef NEWER_REFERENCE_EXT + std::atomic_uint_fast64_t m_refid1; + #else + std::atomic_uint m_refid1; + #endif boost::asio::io_service& m_io_service; basic_otp_mailbox_registry m_mailboxes; diff --git a/include/eixx/connect/basic_otp_node.hxx b/include/eixx/connect/basic_otp_node.hxx index 754fccd..620d4c3 100644 --- a/include/eixx/connect/basic_otp_node.hxx +++ b/include/eixx/connect/basic_otp_node.hxx @@ -92,6 +92,9 @@ template epid basic_otp_node:: create_pid() { + #ifdef NEW_PID_EXT + auto n = m_pid_count.fetch_add(1, std::memory_order_relaxed); + #else int n; while (true) { n = m_pid_count.fetch_add(1, std::memory_order_relaxed); @@ -102,6 +105,7 @@ create_pid() break; } } + #endif return epid(m_nodename, n, m_creation, m_allocator); } @@ -110,7 +114,10 @@ template port basic_otp_node:: create_port() { - int n; + #ifdef NEW_PID_EXT + auto n = m_port_count.fetch_add(1, std::memory_order_relaxed); + #else + int n; while (true) { n = m_port_count.fetch_add(1, std::memory_order_relaxed); if (n < 0x0fffffff /* 28 bits */) break; @@ -120,6 +127,7 @@ create_port() break; } } + #endif return port(m_nodename, n, m_creation, m_allocator); } @@ -128,23 +136,30 @@ template ref basic_otp_node:: create_ref() { - uint_fast64_t n; - int mn; + uint_fast64_t n; + decltype(m_refid1) mo; while (true) { + auto mo = m_refid1.load(std::memory_order_consume); + n = m_refid0.fetch_add(1, std::memory_order_relaxed); if (n) break; - int mo = m_refid1.load(std::memory_order_consume); - mn = mo+1; + auto mn = mo+1; + #ifndef NEWER_REFERENCE_EXT if (mn > 0x3ffff) mn = 0; + #endif if (m_refid1.compare_exchange_weak(mo, mn, std::memory_order_acquire)) break; } - - return ref(m_nodename, mn, n, m_creation, m_allocator); + #ifndef NEWER_REFERENCE_EXT + return ref(m_nodename, {mo >> 32, mo & 0xFFFFffff, n >> 32, n & 0xFFFFffff}, + m_creation, m_allocator); + #else + return ref(m_nodename, mo, n, m_creation, m_allocator); + #endif } template diff --git a/include/eixx/util/hashtable.hpp b/include/eixx/util/hashtable.hpp index 2ccdf7a..9d27c1b 100644 --- a/include/eixx/util/hashtable.hpp +++ b/include/eixx/util/hashtable.hpp @@ -78,14 +78,14 @@ struct hsieh_hash_fun { switch (rem) { case 3: hash += get16bits (data); hash ^= hash << 16; - hash ^= data[sizeof (uint16_t)] << 18; + hash ^= uint32_t(data[sizeof (uint16_t)]) << 18; hash += hash >> 11; break; case 2: hash += get16bits (data); hash ^= hash << 11; hash += hash >> 17; break; - case 1: hash += *data; + case 1: hash += uint32_t(*data); hash ^= hash << 10; hash += hash >> 1; } From 506b26d4427be7a0c1feb2f029f601650954cdc2 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Mon, 20 Sep 2021 22:28:29 +0800 Subject: [PATCH 178/185] fix atom api --- include/eixx/marshal/atom.hpp | 30 ++++++++++++---------- include/eixx/marshal/list.hxx | 2 +- include/eixx/util/atom_table.hpp | 43 ++++++++++++++++++-------------- test/test_eterm.cpp | 17 +++++++------ 4 files changed, 52 insertions(+), 40 deletions(-) diff --git a/include/eixx/marshal/atom.hpp b/include/eixx/marshal/atom.hpp index e1fe9c8..beee171 100644 --- a/include/eixx/marshal/atom.hpp +++ b/include/eixx/marshal/atom.hpp @@ -90,23 +90,24 @@ class atom /// @throw std::runtime_error if atom table is full. /// @throw err_bad_argument if atom length is longer than MAXATOMLEN atom(const char* s) - : m_index(atom_table().lookup(std::string(s))) {} + : m_index((uint32_t)atom_table().lookup(std::string(s))) {} /// @copydoc atom::atom template atom(const char (&s)[N]) - : m_index(atom_table().lookup(std::string(s, N))) {} + : m_index((uint32_t)atom_table().lookup(std::string(s, N))) {} /// @copydoc atom::atom explicit atom(const std::string& s) - : m_index(atom_table().lookup(s)) {} + : m_index((uint32_t)atom_table().lookup(s)) {} /// Try to create an atom without throwing exceptions /// NOTE: if the atom name is invalid or it doesn't exist and \a existing /// is true, then an empty atom is returned. static atom create(const std::string& s, bool existing) { - auto idx = atom_table().try_lookup(s); - return idx <= UINT32_MAX && existing ? atom((uint32_t)idx) : atom(); + auto p = atom_table().try_lookup(s); + BOOST_ASSERT(p.second <= UINT32_MAX); + return p.first && existing ? atom((uint32_t)p.second) : atom(); } /// @copydoc atom::create static atom create(const char* s, bool existing) { @@ -140,12 +141,15 @@ class atom atom(const std::string& s, bool existing) { if (!existing) { - m_index = atom_table().lookup(s); + auto idx = atom_table().lookup(s); + BOOST_ASSERT(idx <= UINT32_MAX); + m_index = (uint32_t)idx; return; } - auto idx = atom_table().try_lookup(s); - if (idx <= UINT32_MAX) - m_index = (uint32_t)idx; + auto p = atom_table().try_lookup(s); + BOOST_ASSERT(p.second <= UINT32_MAX); + if (p.first) + m_index = (uint32_t)p.second; else throw err_atom_not_found(s); } @@ -153,7 +157,7 @@ class atom /// @copydoc atom::atom template explicit atom(const string& s) - : m_index(atom_table().lookup(std::string(s.c_str(), s.size()))) + : m_index((uint32_t)atom_table().lookup(std::string(s.c_str(), s.size()))) {} /// @copydoc atom::atom @@ -162,7 +166,7 @@ class atom atom(const char* s, long n) : atom(s, static_cast(n)) {} /// @copydoc atom::atom atom(const char* s, size_t n) - : m_index(atom_table().lookup(std::string(s, n))) + : m_index((uint32_t)atom_table().lookup(std::string(s, n))) {} /// Copy atom from another atom. This is a constant time @@ -179,7 +183,7 @@ class atom long len = get_len(s, tag); if (len < 0) throw err_decode_exception("Error decoding atom", idx); - m_index = atom_table().lookup(std::string(s, static_cast(len))); + m_index = (uint32_t)atom_table().lookup(std::string(s, static_cast(len))); idx += static_cast(s - s0) + static_cast(len); BOOST_ASSERT((size_t)idx <= a_size); } @@ -194,7 +198,7 @@ class atom uint32_t index() const { return m_index; } void operator= (const atom& s) { m_index = s.m_index; } - void operator= (const std::string& s) { m_index = atom_table().lookup(s); } + void operator= (const std::string& s) { auto idx = atom_table().lookup(s); BOOST_ASSERT(idx <= UINT32_MAX); m_index = (uint32_t)idx; } bool operator== (const char* rhs) const { return strcmp(c_str(), rhs) == 0; } bool operator== (const atom& rhs) const { return m_index == rhs.m_index; } bool operator!= (const char* rhs) const { return !(*this == rhs); } diff --git a/include/eixx/marshal/list.hxx b/include/eixx/marshal/list.hxx index 7d09030..5084fd6 100644 --- a/include/eixx/marshal/list.hxx +++ b/include/eixx/marshal/list.hxx @@ -70,7 +70,7 @@ list::list(const cons_t* a_head, size_t a_len, const Alloc& alloc) if (a_len > 0) { alloc_size = a_len; - } else if (a_len == 0) { + } else { for (const cons_t* p = a_head; p; p = p->next) a_len++; alloc_size = a_len; diff --git a/include/eixx/util/atom_table.hpp b/include/eixx/util/atom_table.hpp index b080120..c2bfd28 100644 --- a/include/eixx/util/atom_table.hpp +++ b/include/eixx/util/atom_table.hpp @@ -72,7 +72,7 @@ namespace util { typename HashMap::const_local_iterator lit = m_index.begin(bucket), lend = m_index.end(bucket); while(lit != lend && strcmp(a_atom, lit->first) != 0) ++lit; - return lit == lend ? (size_t)-1 : lit->second; + return lit == lend ? 0 : lit->second; } public: /// Returns the default atom table maximum size. The value can be @@ -85,8 +85,8 @@ namespace util { std::stringstream ss(p); ss >> n; } - // Hash function only supports up to UINT32_MAX - if (n > UINT32_MAX+1) n = UINT32_MAX+1; + // Reserve capacity up to UINT32_MAX + if (n > UINT32_MAX) n = UINT32_MAX; return n > 0 ? n : s_default_max_atoms; } @@ -121,16 +121,20 @@ namespace util { /// Try to lookup an atom in the atom table /// @return -1 if the atom by name is not found, -2 if the atom is invalid, /// or a value >= 0, if an existing atom is found. - size_t try_lookup(const char* a_name, size_t n) { return try_lookup(String(a_name, n)); } - size_t try_lookup(const char* a_name) { return try_lookup(String(a_name)); } - size_t try_lookup(const String& a_name) + std::pair try_lookup(const char* a_name, size_t n) { return try_lookup(String(a_name, n)); } + std::pair try_lookup(const char* a_name) { return try_lookup(String(a_name)); } + std::pair try_lookup(const String& a_name) { if (a_name.size() == 0) - return 0; + return {true, 0}; if (a_name.size() > MAXATOMLEN_UTF8 || utf8_length(a_name) > MAXATOMLEN) - return (size_t)-2; + return {false, 2}; size_t bucket = m_index.bucket(a_name.c_str()); - return find_value(bucket, a_name.c_str()); + size_t n = find_value(bucket, a_name.c_str()); + if (n > 0) + return {true, n}; + else + return {false, 1}; } /// Lookup an atom in the atom table by name. If the atom is not @@ -138,28 +142,29 @@ namespace util { /// atom in the atom table. /// @throw std::runtime_error if atom table is full. /// @throw err_bad_argument if atom size is longer than MAXATOMLEN - uint32_t lookup(const char* a_name, size_t n) { return lookup(String(a_name, n)); } - uint32_t lookup(const char* a_name) { return lookup(String(a_name)); } - uint32_t lookup(const String& a_name) + size_t lookup(const char* a_name, size_t n) { return lookup(String(a_name, n)); } + size_t lookup(const char* a_name) { return lookup(String(a_name)); } + size_t lookup(const String& a_name) { - size_t n = try_lookup(a_name); - if (n <= UINT32_MAX) return (uint32_t)n; - if (n == (size_t)-2) throw err_bad_argument("Atom size is too long!"); + std::pair p = try_lookup(a_name); + size_t n = p.second; + if (p.first) return n; + if (!p.first && n == 2) throw err_bad_argument("Atom size is too long!"); lock_guard guard(m_lock); if (!std::is_same::value) { size_t bucket = m_index.bucket(a_name.c_str()); n = find_value(bucket, a_name.c_str()); - if (n <= UINT32_MAX) - return (uint32_t)n; + if (n > 0) + return n; } n = m_atoms.size(); - if (n > UINT32_MAX || (n+1) == m_atoms.capacity()) + if (n == m_atoms.capacity()) throw std::runtime_error("Atom hash table is full!"); m_atoms.push_back(a_name); m_index[m_atoms.back().c_str()] = n; - return (uint32_t)n; + return n; } private: Vector m_atoms; diff --git a/test/test_eterm.cpp b/test/test_eterm.cpp index 02f2311..c4f5de7 100644 --- a/test/test_eterm.cpp +++ b/test/test_eterm.cpp @@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE( test_atomable ) util::atom_table t(10); BOOST_CHECK_EQUAL(0, t.lookup(std::string())); BOOST_CHECK_EQUAL(0, t.lookup("")); - uint32_t n = t.lookup("abc"); + auto n = t.lookup("abc"); BOOST_CHECK(0 < n); BOOST_CHECK(0 < t.lookup("aaaaa")); BOOST_CHECK_EQUAL(n, t.lookup("abc")); @@ -77,13 +77,16 @@ BOOST_AUTO_TEST_CASE( test_atom ) BOOST_CHECK_EQUAL("temp2", am_temp2); } { - auto n = util::atom_table().try_lookup("temp3"); - BOOST_CHECK_EQUAL(-1, n); + auto p = util::atom_table().try_lookup("temp3"); + BOOST_CHECK_EQUAL(false, p.first); + BOOST_CHECK_EQUAL(1, p.second); auto s = std::string(MAXATOMLEN+1, 'X'); - n = util::atom_table().try_lookup(s); - BOOST_CHECK_EQUAL(-2, n); - n = util::atom_table().try_lookup(""); - BOOST_CHECK_EQUAL(0, n); + p = util::atom_table().try_lookup(s); + BOOST_CHECK_EQUAL(false, p.first); + BOOST_CHECK_EQUAL(2, p.second); + p = util::atom_table().try_lookup(""); + BOOST_CHECK_EQUAL(true, p.first); + BOOST_CHECK_EQUAL(0, p.second); BOOST_CHECK_THROW(atom("temp3", true), err_atom_not_found); auto a = atom("temp3", false); From 20bf90bdb07fa4e777340870a3ff8f2a97ba6545 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Mon, 20 Sep 2021 23:16:32 +0800 Subject: [PATCH 179/185] fix warning on port and epid creation --- include/eixx/connect/basic_otp_node.hxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/eixx/connect/basic_otp_node.hxx b/include/eixx/connect/basic_otp_node.hxx index ed30a83..3dbd1cf 100644 --- a/include/eixx/connect/basic_otp_node.hxx +++ b/include/eixx/connect/basic_otp_node.hxx @@ -100,9 +100,9 @@ epid basic_otp_node:: create_pid() { #ifdef NEW_PID_EXT - auto n = m_pid_count.fetch_add(1, std::memory_order_relaxed); + uint32_t n = m_pid_count.fetch_add(1, std::memory_order_relaxed); #else - int n; + uint32_t n; while (true) { n = m_pid_count.fetch_add(1, std::memory_order_relaxed); if (n < 0x0fffffff /* 28 bits */) break; @@ -122,9 +122,9 @@ port basic_otp_node:: create_port() { #ifdef NEW_PID_EXT - auto n = m_port_count.fetch_add(1, std::memory_order_relaxed); + uint64_t n = m_port_count.fetch_add(1, std::memory_order_relaxed); #else - int n; + uint64_t n; while (true) { n = m_port_count.fetch_add(1, std::memory_order_relaxed); if (n < 0x0fffffff /* 28 bits */) break; From 3e7f647d68e7a395273e19862b8aa13185e24ff6 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Tue, 21 Sep 2021 01:31:52 +0800 Subject: [PATCH 180/185] fix list constructor --- include/eixx/marshal/list.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/eixx/marshal/list.hpp b/include/eixx/marshal/list.hpp index 6d3e151..8f7da01 100644 --- a/include/eixx/marshal/list.hpp +++ b/include/eixx/marshal/list.hpp @@ -139,10 +139,11 @@ class list : protected alloc_base, Alloc> { /// /// When a_estimated_size is 0, an empty initialized list is created. Otherwise, /// the list is not initialized. - explicit list(int a_estimated_size, const Alloc& alloc = Alloc()) { + explicit list(int a_estimated_size, const Alloc& alloc = Alloc()) + : list((size_t)a_estimated_size, alloc) + { if (a_estimated_size < 0) throw err_bad_argument("List too short"); - list((size_t)a_estimated_size, alloc); } /// Construct a list with a given estimated size. From d2d79d8df43f4a7a147fe5eabc8d6df8c8ae0c64 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 28 Sep 2021 17:39:28 -0400 Subject: [PATCH 181/185] Fix warnings --- include/eixx/connect/basic_otp_node.hxx | 7 +++---- include/eixx/connect/transport_otp_connection.hxx | 4 ++-- include/eixx/connect/transport_otp_connection_tcp.hxx | 2 +- test/test_perf.cpp | 10 +++++----- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/eixx/connect/basic_otp_node.hxx b/include/eixx/connect/basic_otp_node.hxx index 3dbd1cf..e4fc8d2 100644 --- a/include/eixx/connect/basic_otp_node.hxx +++ b/include/eixx/connect/basic_otp_node.hxx @@ -104,7 +104,7 @@ create_pid() #else uint32_t n; while (true) { - n = m_pid_count.fetch_add(1, std::memory_order_relaxed); + n = uint32_t(m_pid_count.fetch_add(1, std::memory_order_relaxed)); if (n < 0x0fffffff /* 28 bits */) break; if (m_pid_count.exchange(1, std::memory_order_acquire) == 1) { @@ -147,9 +147,8 @@ create_ref() decltype(m_refid1) mo; while (true) { - auto mo = m_refid1.load(std::memory_order_consume); - - n = m_refid0.fetch_add(1, std::memory_order_relaxed); + mo = m_refid1.load(std::memory_order_consume); + n = m_refid0.fetch_add(1, std::memory_order_relaxed); if (n) break; auto mn = mo+1; diff --git a/include/eixx/connect/transport_otp_connection.hxx b/include/eixx/connect/transport_otp_connection.hxx index 530a0db..69bb4e4 100644 --- a/include/eixx/connect/transport_otp_connection.hxx +++ b/include/eixx/connect/transport_otp_connection.hxx @@ -255,7 +255,7 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) } } - long need_bytes = m_packet_size + s_header_size - rd_length(); + auto need_bytes = m_packet_size + s_header_size - rd_length(); /* if (unlikely(verbose() >= VERBOSE_WIRE)) @@ -297,7 +297,7 @@ handle_read(const boost::system::error_code& err, size_t bytes_transferred) to_binary_string(m_rd_ptr, m_packet_size)); } m_rd_ptr += m_packet_size; - m_got_header = rd_length() >= (long)s_header_size; + m_got_header = rd_length() >= long(s_header_size); if (m_got_header) { m_packet_size = cast_be(m_rd_ptr); need_bytes = m_packet_size + s_header_size - rd_length(); diff --git a/include/eixx/connect/transport_otp_connection_tcp.hxx b/include/eixx/connect/transport_otp_connection_tcp.hxx index fd93410..198ac44 100644 --- a/include/eixx/connect/transport_otp_connection_tcp.hxx +++ b/include/eixx/connect/transport_otp_connection_tcp.hxx @@ -268,7 +268,7 @@ void tcp_connection::handle_epmd_read_body( m_epmd_wr += bytes_transferred; #ifndef NDEBUG - size_t got_bytes = m_epmd_wr - m_buf_epmd; + auto got_bytes = m_epmd_wr - m_buf_epmd; #endif BOOST_ASSERT(got_bytes >= 10); diff --git a/test/test_perf.cpp b/test/test_perf.cpp index a570dbd..3c7000f 100644 --- a/test/test_perf.cpp +++ b/test/test_perf.cpp @@ -77,7 +77,7 @@ int main(int argc, char* argv[]) { atom a("test"); int k = 0; for (int j=0; j < iterations; j++) - { atom t("test"); if (t==a) k++; size += eterm(t).encode_size(); } + { atom t1("test"); if (t1==a) k++; size += eterm(t1).encode_size(); } t.sample("Atom2", true, size); } static const char* ss="This is a test string. This is a test string. This is a test string."; @@ -88,8 +88,8 @@ int main(int argc, char* argv[]) { { binary b(ss, sizeof(ss)); for (int j=0; j < iterations; j++) { - eterm t(b); - size += t.encode_size(); + eterm t1(b); + size += t1.encode_size(); } t.sample("Binary2", true, size); } @@ -97,7 +97,7 @@ int main(int argc, char* argv[]) { eterm l[] = { eterm(10), eterm("atom_value"), eterm(true) }; for (int j=0; j < iterations; j++) - { tuple t(l); size += eterm(t).encode_size(); } + { tuple t1(l); size += eterm(t1).encode_size(); } t.sample("Tuple1", true, size); { tuple tup(l); @@ -106,7 +106,7 @@ int main(int argc, char* argv[]) { t.sample("Tuple2", true, size); } for (int j=0; j < iterations; j++) - { list t(l); size += eterm(t).encode_size(); } + { list t1(l); size += eterm(t1).encode_size(); } t.sample("List1", true, size); { list ll(l); From d3b9d96c6d5a9ba855e0cc9b2cf9be7f2e8026e6 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 26 Oct 2022 05:14:40 -0400 Subject: [PATCH 182/185] Add else clause --- include/eixx/marshal/eterm.hxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/eixx/marshal/eterm.hxx b/include/eixx/marshal/eterm.hxx index e68031a..e722805 100644 --- a/include/eixx/marshal/eterm.hxx +++ b/include/eixx/marshal/eterm.hxx @@ -47,8 +47,8 @@ inline eterm_type type_string_to_type(const char* s, size_t n) { switch (s[0]) { case 'i': - if (strncmp(p,"nt",m) == 0) r = LONG; - if (strncmp(p,"nteger",m) == 0) r = LONG; + if (strncmp(p,"nt",m)==0) r = LONG; + else if (strncmp(p,"nteger",m)==0) r = LONG; break; case 'd': if (strncmp(p,"ouble",m) == 0) r = DOUBLE; @@ -76,8 +76,8 @@ inline eterm_type type_string_to_type(const char* s, size_t n) { else if (strncmp(p,"ort",m) == 0) r = PORT; break; case 'r': - if (strncmp(p,"ef",m) == 0) r = REF; - else if (strncmp(p,"eference",m) == 0) r = REF; + if (strncmp(p,"ef",m) == 0) r = REF; + else if (strncmp(p,"eference",m)==0)r = REF; break; case 'v': if (strncmp(p,"ar",m) == 0) r = VAR; From d16480601e8a1117e4e0234e402aac3e66621dc2 Mon Sep 17 00:00:00 2001 From: Alex Pol Date: Tue, 21 May 2024 12:52:52 +0300 Subject: [PATCH 183/185] moving to the latest eixx version --- include/eixx/eterm.hpp | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index e075500..a0a4f0f 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -28,7 +28,6 @@ limitations under the License. #ifndef _EIXX_ETERM_HPP_ #define _EIXX_ETERM_HPP_ -#include #include #include @@ -38,24 +37,24 @@ limitations under the License. namespace eixx { -typedef marshal::eterm eterm; -typedef marshal::atom atom; -typedef marshal::string string; -typedef marshal::binary binary; -typedef marshal::epid epid; -typedef marshal::port port; -typedef marshal::ref ref; -typedef marshal::tuple tuple; -typedef marshal::list list; -typedef marshal::map map; -typedef marshal::trace trace; -typedef marshal::var var; -typedef marshal::varbind varbind; -typedef marshal::eterm_pattern_matcher eterm_pattern_matcher; -typedef marshal::eterm_pattern_action eterm_pattern_action; +typedef marshal::eterm eterm; +typedef marshal::atom atom; +typedef marshal::string string; +typedef marshal::binary binary; +typedef marshal::epid epid; +typedef marshal::port port; +typedef marshal::ref ref; +typedef marshal::tuple tuple; +typedef marshal::list list; +typedef marshal::map map; +typedef marshal::trace trace; +typedef marshal::var var; +typedef marshal::varbind varbind; +typedef marshal::eterm_pattern_matcher eterm_pattern_matcher; +typedef marshal::eterm_pattern_action eterm_pattern_action; namespace detail { - BOOST_STATIC_ASSERT(sizeof(eterm) == (ALIGNOF_UINT64_T > sizeof(int) ? ALIGNOF_UINT64_T : sizeof(int)) + sizeof(uint64_t)); + BOOST_STATIC_ASSERT(sizeof(eterm) == (alignof(uint64_t) > sizeof(int) ? alignof(uint64_t) : sizeof(int)) + sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(atom) <= sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(string) <= sizeof(uint64_t)); BOOST_STATIC_ASSERT(sizeof(binary) <= sizeof(uint64_t)); From 76ce0bb554683348e339447ae05c00309e8add15 Mon Sep 17 00:00:00 2001 From: Alex Pol Date: Thu, 30 May 2024 15:20:15 +0300 Subject: [PATCH 184/185] revert namespace --- include/eixx/eterm.hpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/include/eixx/eterm.hpp b/include/eixx/eterm.hpp index a0a4f0f..55113fe 100644 --- a/include/eixx/eterm.hpp +++ b/include/eixx/eterm.hpp @@ -37,21 +37,21 @@ limitations under the License. namespace eixx { -typedef marshal::eterm eterm; +typedef marshal::eterm eterm; typedef marshal::atom atom; -typedef marshal::string string; -typedef marshal::binary binary; -typedef marshal::epid epid; -typedef marshal::port port; -typedef marshal::ref ref; -typedef marshal::tuple tuple; -typedef marshal::list list; -typedef marshal::map map; -typedef marshal::trace trace; +typedef marshal::string string; +typedef marshal::binary binary; +typedef marshal::epid epid; +typedef marshal::port port; +typedef marshal::ref ref; +typedef marshal::tuple tuple; +typedef marshal::list list; +typedef marshal::map map; +typedef marshal::trace trace; typedef marshal::var var; -typedef marshal::varbind varbind; -typedef marshal::eterm_pattern_matcher eterm_pattern_matcher; -typedef marshal::eterm_pattern_action eterm_pattern_action; +typedef marshal::varbind varbind; +typedef marshal::eterm_pattern_matcher eterm_pattern_matcher; +typedef marshal::eterm_pattern_action eterm_pattern_action; namespace detail { BOOST_STATIC_ASSERT(sizeof(eterm) == (alignof(uint64_t) > sizeof(int) ? alignof(uint64_t) : sizeof(int)) + sizeof(uint64_t)); From 854320a8c8dc22a95da8ee108eed3798e053a57a Mon Sep 17 00:00:00 2001 From: "abhilash.ramadugu" Date: Tue, 9 Jul 2024 19:46:32 +0530 Subject: [PATCH 185/185] fixed the config.h --- include/eixx/config.h | 291 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 include/eixx/config.h diff --git a/include/eixx/config.h b/include/eixx/config.h new file mode 100644 index 0000000..99b16bb --- /dev/null +++ b/include/eixx/config.h @@ -0,0 +1,291 @@ +#ifndef _INCLUDE_EIXX_CONFIG_H +#define _INCLUDE_EIXX_CONFIG_H 1 + +/* include/eixx/config.h. Generated automatically at end of configure. */ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Algorithm AES in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_AES +#define EIXX_CRYPTO_WITH_AES 1 +#endif + +/* Algorithm BF in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_BF +#define EIXX_CRYPTO_WITH_BF 1 +#endif + +/* Algorithm CAMELLIA in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_CAMELLIA +#define EIXX_CRYPTO_WITH_CAMELLIA 1 +#endif + +/* Algorithm CAST in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_CAST +#define EIXX_CRYPTO_WITH_CAST 1 +#endif + +/* Algorithm DES in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_DES +#define EIXX_CRYPTO_WITH_DES 1 +#endif + +/* Algorithm DH in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_DH +#define EIXX_CRYPTO_WITH_DH 1 +#endif + +/* Algorithm DSA in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_DSA +#define EIXX_CRYPTO_WITH_DSA 1 +#endif + +/* Algorithm IDEA in openssl crypto library */ +/* #undef CRYPTO_WITH_IDEA */ + +/* Algorithm MD2 in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_MD2 +#define EIXX_CRYPTO_WITH_MD2 1 +#endif + +/* Algorithm MD4 in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_MD4 +#define EIXX_CRYPTO_WITH_MD4 1 +#endif + +/* Algorithm MD5 in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_MD5 +#define EIXX_CRYPTO_WITH_MD5 1 +#endif + +/* Algorithm RC2 in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_RC2 +#define EIXX_CRYPTO_WITH_RC2 1 +#endif + +/* Algorithm RC5 in openssl crypto library */ +/* #undef CRYPTO_WITH_RC5 */ + +/* Algorithm RIPEMD in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_RIPEMD +#define EIXX_CRYPTO_WITH_RIPEMD 1 +#endif + +/* Algorithm RSA in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_RSA +#define EIXX_CRYPTO_WITH_RSA 1 +#endif + +/* Algorithm SHA in openssl crypto library */ +#ifndef EIXX_CRYPTO_WITH_SHA +#define EIXX_CRYPTO_WITH_SHA 1 +#endif + +/* define if the Boost library is available */ +#ifndef EIXX_HAVE_BOOST +#define EIXX_HAVE_BOOST /**/ +#endif + +/* define if the Boost::ASIO library is available */ +#ifndef EIXX_HAVE_BOOST_ASIO +#define EIXX_HAVE_BOOST_ASIO /**/ +#endif + +/* define if the Boost::Date_Time library is available */ +#ifndef EIXX_HAVE_BOOST_DATE_TIME +#define EIXX_HAVE_BOOST_DATE_TIME /**/ +#endif + +/* define if the Boost::System library is available */ +#ifndef EIXX_HAVE_BOOST_SYSTEM +#define EIXX_HAVE_BOOST_SYSTEM /**/ +#endif + +/* define if the Boost::Thread library is available */ +#ifndef EIXX_HAVE_BOOST_THREAD +#define EIXX_HAVE_BOOST_THREAD /**/ +#endif + +/* define if the Boost::Unit_Test_Framework library is available */ +#ifndef EIXX_HAVE_BOOST_UNIT_TEST_FRAMEWORK +#define EIXX_HAVE_BOOST_UNIT_TEST_FRAMEWORK /**/ +#endif + +/* Openssl crypto library is available */ +#ifndef EIXX_HAVE_CRYPTO +#define EIXX_HAVE_CRYPTO 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_DLFCN_H +#define EIXX_HAVE_DLFCN_H 1 +#endif + +/* erl_interface/src/epmd/ei_epmd.h is available */ +#ifndef EIXX_HAVE_EI_EPMD +#define EIXX_HAVE_EI_EPMD 1 +#endif + +/* Define to 1 if you have the `gettimeofday' function. */ +#ifndef EIXX_HAVE_GETTIMEOFDAY +#define EIXX_HAVE_GETTIMEOFDAY 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_INTTYPES_H +#define EIXX_HAVE_INTTYPES_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_MEMORY_H +#define EIXX_HAVE_MEMORY_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_OPENSSL_MD5_H +#define EIXX_HAVE_OPENSSL_MD5_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_OPENSSL_OPENSSLCONF_H +#define EIXX_HAVE_OPENSSL_OPENSSLCONF_H 1 +#endif + +/* Define to 1 if you have the `socket' function. */ +#ifndef EIXX_HAVE_SOCKET +#define EIXX_HAVE_SOCKET 1 +#endif + +/* Define to 1 if you have the `sqrt' function. */ +/* #undef HAVE_SQRT */ + +/* Define to 1 if stdbool.h conforms to C99. */ +#ifndef EIXX_HAVE_STDBOOL_H +#define EIXX_HAVE_STDBOOL_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_STDINT_H +#define EIXX_HAVE_STDINT_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_STDLIB_H +#define EIXX_HAVE_STDLIB_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_STRINGS_H +#define EIXX_HAVE_STRINGS_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_STRING_H +#define EIXX_HAVE_STRING_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_SYS_STAT_H +#define EIXX_HAVE_SYS_STAT_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_SYS_TIME_H +#define EIXX_HAVE_SYS_TIME_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_SYS_TYPES_H +#define EIXX_HAVE_SYS_TYPES_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef EIXX_HAVE_UNISTD_H +#define EIXX_HAVE_UNISTD_H 1 +#endif + +/* Define to 1 if the system has the type `_Bool'. */ +#ifndef EIXX_HAVE__BOOL +#define EIXX_HAVE__BOOL 1 +#endif + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#ifndef EIXX_LT_OBJDIR +#define EIXX_LT_OBJDIR ".libs/" +#endif + +/* Name of package */ +#ifndef EIXX_PACKAGE +#define EIXX_PACKAGE "eixx" +#endif + +/* Define to the address where bug reports for this package should be sent. */ +#ifndef EIXX_PACKAGE_BUGREPORT +#define EIXX_PACKAGE_BUGREPORT "BUG-REPORT-ADDRESS" +#endif + +/* Define to the full name of this package. */ +#ifndef EIXX_PACKAGE_NAME +#define EIXX_PACKAGE_NAME "eixx" +#endif + +/* Define to the full name and version of this package. */ +#ifndef EIXX_PACKAGE_STRING +#define EIXX_PACKAGE_STRING "eixx 0.1" +#endif + +/* Define to the one symbol short name of this package. */ +#ifndef EIXX_PACKAGE_TARNAME +#define EIXX_PACKAGE_TARNAME "eixx" +#endif + +/* Define to the home page for this package. */ +#ifndef EIXX_PACKAGE_URL +#define EIXX_PACKAGE_URL "" +#endif + +/* Define to the version of this package. */ +#ifndef EIXX_PACKAGE_VERSION +#define EIXX_PACKAGE_VERSION "0.1" +#endif + +/* Define to 1 if you have the ANSI C header files. */ +#ifndef EIXX_STDC_HEADERS +#define EIXX_STDC_HEADERS 1 +#endif + +/* Version number of package */ +#ifndef EIXX_VERSION +#define EIXX_VERSION "0.1" +#endif + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT64_T */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint64_t */ + +/* once: _INCLUDE_EIXX_CONFIG_H */ +#endif