Eric Ramat преди 1 година
родител
ревизия
8b34a6d824
променени са 4 файла, в които са добавени 251 реда и са изтрити 227 реда
  1. 1 2
      src/artis-star/common/event/CMakeLists.txt
  2. 1 95
      src/artis-star/common/event/Value.cpp
  3. 112 125
      src/artis-star/common/event/Value.hpp
  4. 137 5
      tests/common_value.cpp

+ 1 - 2
src/artis-star/common/event/CMakeLists.txt

@@ -11,5 +11,4 @@ SET(COMMON_EVENT_CPP Value.cpp)
 
 ADD_SOURCES(artislib ${COMMON_EVENT_HPP} ${COMMON_EVENT_CPP})
 
-INSTALL(FILES ${COMMON_EVENT_HPP} DESTINATION
-        ${ARTIS_STAR_INCLUDE_DIRS}/common/event)
+INSTALL(FILES ${COMMON_EVENT_HPP} DESTINATION ${ARTIS_STAR_INCLUDE_DIRS}/common/event)

+ 1 - 95
src/artis-star/common/event/Value.cpp

@@ -28,103 +28,9 @@
 
 namespace artis::common::event {
 
-const Value::ConvertFunctions Value::convert = {
-  {
-    typeid(double).hash_code(),         [](const Value &value) {
-    double v;
-
-    value.operator()(v);
-    return std::to_string(v);
-  }},
-  {
-    typeid(int).hash_code(),            [](const Value &value) {
-    int v;
-
-    value.operator()(v);
-    return std::to_string(v);
-  }},
-  {
-    typeid(unsigned int).hash_code(),   [](const Value &value) {
-    unsigned int v;
-
-    value.operator()(v);
-    return std::to_string(v);
-  }},
-  {
-    typeid(bool).hash_code(),           [](const Value &value) {
-    bool v;
-
-    value.operator()(v);
-    return v ? "true" : "false";
-  }},
-  {
-    typeid(char).hash_code(),           [](const Value &value) {
-    char v;
-
-    value.operator()(v);
-    return std::string(&v, 1);
-  }},
-  {
-    typeid(double *).hash_code(),       [](const Value &value) {
-
-    double *v;
-    std::string str;
-    size_t size = value._size / sizeof(double);
-
-    value.operator()(v);
-    for (size_t i = 0; i < size; ++i) {
-      str += std::to_string(v[i]) + std::string(" ");
-    }
-    return str;
-  }},
-  {
-    typeid(int *).hash_code(),          [](const Value &value) {
-    int *v;
-    std::string str;
-    size_t size = value._size / sizeof(int);
-
-    value.operator()(v);
-    for (size_t i = 0; i < size; ++i) {
-      str += std::to_string(v[i]) + std::string(" ");
-    }
-    return str;
-  }},
-  {
-    typeid(unsigned int *).hash_code(), [](const Value &value) {
-    unsigned int *v;
-    std::string str;
-    size_t size = value._size / sizeof(unsigned int);
-
-    value.operator()(v);
-    for (size_t i = 0; i < size; ++i) {
-      str += std::to_string(v[i]) + std::string(" ");
-    }
-    return str;
-  }},
-  {
-    typeid(bool *).hash_code(),         [](const Value &value) {
-    bool *v;
-    std::string str;
-    size_t size = value._size / sizeof(bool);
-
-    value.operator()(v);
-    for (size_t i = 0; i < size; ++i) {
-      str += (v[i] ? "true" : "false") + std::string(" ");
-    }
-    return str;
-  }},
-  {
-    typeid(char *).hash_code(),         [](const Value &value) {
-    char *v;
-
-    value.operator()(v);
-    return std::string(v, value._size / sizeof(char));
-  }
-  }};
-
 std::ostream &operator<<(std::ostream &o, const artis::common::event::Value &value) {
   o << value.to_string();
   return o;
 }
 
-} // namespace artis common event
+}

+ 112 - 125
src/artis-star/common/event/Value.hpp

@@ -28,183 +28,170 @@
 #define COMMON_EVENT_VALUE
 
 #include <boost/serialization/serialization.hpp>
-#include <boost/serialization/array.hpp>
 
-#include <cassert>
-#include <cstring>
-#include <functional>
-#include <map>
-#include <numeric>
+#include <any>
+#include <memory>
+#include <sstream>
 #include <string>
-#include <typeinfo>
+#include <type_traits>
+#include <valarray>
 #include <vector>
 
 namespace artis::common::event {
 
+template<typename T>
+struct HasToString {
+  template<typename U, std::string (U::*)() const>
+  struct SFINAE {
+  };
+
+  template<typename U>
+  static char Test(SFINAE<U, &U::to_string> *);
+
+  template<typename U>
+  static int Test(...);
+
+  static const bool Has = sizeof(Test<T>(0)) == sizeof(char);
+};
+
 class Value {
-public:
-  Value()
-    : _content(nullptr), _size(0), _type_id(0) {}
 
-  template<typename T>
-  Value(const T &value) { assign(&value, sizeof(T), typeid(T).hash_code()); }
+  class Base {
+  public:
+    virtual ~Base() = default;
 
-  template<typename T>
-  Value(const T *value, size_t size) { assign(value, sizeof(T) * size, typeid(T *).hash_code()); }
+    virtual bool operator==(const Base &other) const = 0;
 
-  template<typename T>
-  Value(const std::vector<T> &value) {
-    const T *v = value.data();
+    virtual std::string to_string() const = 0;
 
-    assign(v, sizeof(T) * value.size(), typeid(T *).hash_code());
-  }
+    virtual const std::type_info &type() const noexcept = 0;
+  };
 
-  Value(const std::vector<bool> &value) {
-    size_t size = sizeof(bool) * value.size();
+  template<typename T>
+  class Data : public Base, public std::any {
+  public:
+    template<typename U = T, std::enable_if_t<not std::is_same_v<U, std::string>, bool> = true>
+    Data(const U &value) : std::any(value) {}
 
-    _content = new char[size];
-    for (size_t i = 0; i < value.size(); ++i) {
-      _content[i] = value[i];
-    }
-    _size = size;
-    _type_id = typeid(bool *).hash_code();
-  }
+    Data(const std::string &value) : std::any(value) {}
 
-  Value(void *content, size_t size) { assign(content, size, typeid(void *).hash_code()); }
+    Data(const std::valarray<T> &value) : std::any(value) {}
 
-  Value(const char *value, unsigned int size) { assign(value, size * sizeof(char), typeid(char *).hash_code()); }
+    Data(const std::vector<T> &value) : std::any(value) {}
 
-  Value(const Value &value) {
-    if (value._content != nullptr) {
-      assign(value._content, value._size, value._type_id);
-    } else {
-      _content = nullptr;
-      _size = 0;
-      _type_id = 0;
+    bool operator==(const Base &other) const override {
+      return type() == other.type() and
+             std::any_cast<const T &>(*this) == std::any_cast<const T &>(*dynamic_cast<const Data<T> *>(&other));
     }
-  }
 
-  Value(Value &&value) : _content(value._content), _size(value._size), _type_id(value._type_id) {
-    value._content = nullptr;
-    value._size = 0;
-    value._type_id = 0;
-  }
+    template<typename U>
+    void operator()(U &value) const {
+      value = std::any_cast<const U &>(*this);
+    }
 
-  virtual ~Value() {
-    delete[] _content;
-  }
+    std::string to_string() const override {
+      std::stringstream ss;
+
+      if constexpr (HasToString<T>::Has) {
+        if (type() == typeid(std::vector<T>)) {
+          const std::vector<T> &values = std::any_cast<const std::vector<T> &>(*this);
+
+          for (const auto &e: values) {
+            ss << std::boolalpha << e.to_string() << " ";
+          }
+        } else {
+          ss << std::any_cast<const T &>(*this).to_string();
+        }
+      } else {
+        if (type() == typeid(std::string)) {
+          ss << std::any_cast<const std::string &>(*this);
+        } else if (type() == typeid(std::valarray<T>)) {
+          const std::valarray<T> &values = std::any_cast<const std::valarray<T> &>(*this);
+
+          for (const auto &e: values) {
+            ss << std::boolalpha << e << " ";
+          }
+        } else if (type() == typeid(std::vector<T>)) {
+          const std::vector<T> &values = std::any_cast<const std::vector<T> &>(*this);
+
+          for (const auto &e: values) {
+            ss << std::boolalpha << e << " ";
+          }
+        } else {
+          ss << std::boolalpha << std::any_cast<const T &>(*this);
+        }
+      }
+      return ss.str();
+    }
 
-  bool is_null() const { return _content == nullptr; }
+    const std::type_info &type() const noexcept override { return std::any::type(); }
 
-  template<typename Z>
-  bool is_type() const { return _type_id == typeid(Z).hash_code(); }
+  private:
+    using _type = T;
+  };
 
-  bool operator==(const Value &other) const {
-    return _type_id == other._type_id and _size == other._size
-           and std::memcmp(_content, other._content, _size) == 0;
-  }
-
-  template<typename T>
-  void operator()(T &value) const {
+public:
+  Value() : _data(nullptr) {}
 
-    assert(_type_id == typeid(T).hash_code());
+  Value(const Value& value) : _data(value._data) {}
 
-    value = *(T *) (_content);
-  }
+  template<typename T, std::enable_if_t<not HasToString<T>::Has, bool> = true>
+  Value(const T &value) : _data(new Data<T>(value)) {}
 
   template<typename T>
-  void operator()(T *&value) const {
+  Value(const std::vector<T> &value) : _data(new Data<T>(value)) {}
 
-    assert(_type_id == typeid(T *).hash_code());
+  template<typename T, std::enable_if_t<HasToString<T>::Has, bool> = true>
+  Value(const T &value) : _data(new Data<T>(value)) {}
 
-    value = (T *) (_content);
-  }
+  template<typename T, size_t size, std::enable_if_t<std::is_same<T, char>::value, bool> = true>
+  Value(const T (&value)[size]) : _data(new Data<T>(std::string(value, size))) {}
 
   template<typename T>
-  void operator()(std::vector<T> &value) const {
-    assert(_type_id == typeid(T *).hash_code());
+  Value(const T *value, size_t size) : _data(new Data<T>(std::valarray<T>(value, size))) {}
 
-    size_t size = _size / sizeof(T);
+  bool is_null() const { return _data.get() == nullptr; }
 
-    for (size_t i = 0; i < size; ++i) {
-      value.push_back(((T *) (_content))[i]);
-    }
-  }
+  template<typename Z>
+  bool is_type() const { return _data->type() == typeid(Z); }
 
-  Value &operator=(const Value &value) {
-    delete[] _content;
-    if (value._content != nullptr) {
-      assign(value._content, value._size, value._type_id);
-    } else {
-      _content = nullptr;
-      _size = 0;
-      _type_id = 0;
-    }
+  Value& operator=(const Value &other) {
+    _data = other._data;
     return *this;
   }
 
-  Value &operator=(Value &&value) {
-    delete[] _content;
-    _content = value._content;
-    value._content = nullptr;
-    _size = value._size;
-    value._size = 0;
-    _type_id = value._type_id;
-    value._type_id = 0;
-    return *this;
+  bool operator==(const Value &other) const {
+    return _data->operator==(*other._data);
   }
 
-  template<typename Z>
-  size_t size() const {
+  template<typename T>
+  void operator()(T &value) const {
+    dynamic_cast<Data<T> *>(_data.get())->operator()(value);
+  }
 
-    assert(is_type<Z *>());
+  template<typename T>
+  void operator()(std::vector<T> &value) const {
+    dynamic_cast<Data<T> *>(_data.get())->operator()(value);
+  }
 
-    return _size / sizeof(Z);
+  template<typename T>
+  void operator()(std::valarray<T> &value) const {
+    dynamic_cast<Data<T> *>(_data.get())->operator()(value);
   }
 
   std::string to_string() const {
-    if (is_null()) {
-      return "<null>";
-    }
-
-    auto it = convert.find(_type_id);
-
-    if (it != convert.cend()) {
-      return it->second(*this);
-    }
-    return "<unstringify>";
+    return _data->to_string();
   }
 
 private:
-  typedef std::map<unsigned long, std::function<std::string(const artis::common::event::Value &)>> ConvertFunctions;
-
-  static const ConvertFunctions convert;
-
-  void assign(const void *content, size_t size, size_t type_id) {
-    _content = new char[size];
-    std::memcpy(_content, content, size);
-    _size = size;
-    _type_id = type_id;
-  }
-
   friend class boost::serialization::access;
 
   template<typename Archive>
   void serialize(Archive &ar, const unsigned int version) {
-    (void) version;
-
-    ar & _size;
-    if (Archive::is_loading::value) {
-      assert(_content == nullptr);
-      _content = new char[_size];
-    }
-    ar & boost::serialization::make_array<char>(_content, _size);
-    ar & _type_id;
+    // TODO
   }
 
-  char *_content = nullptr;
-  size_t _size = 0;
-  size_t _type_id = 0;
+  std::shared_ptr<Base> _data;
 };
 
 std::ostream& operator<<(std::ostream& o, const artis::common::event::Value& value);

+ 137 - 5
tests/common_value.cpp

@@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(Common_Value_TestCase_2)
 
   BOOST_REQUIRE_EQUAL(int_value.to_string(), "1");
   BOOST_REQUIRE_EQUAL(unsigned_int_value.to_string(), "1");
-  BOOST_REQUIRE_EQUAL(double_value.to_string(), "0.500000");
+  BOOST_REQUIRE_EQUAL(double_value.to_string(), "0.5");
   BOOST_REQUIRE_EQUAL(bool_value.to_string(), "true");
   BOOST_REQUIRE_EQUAL(char_value.to_string(), "a");
 }
@@ -68,20 +68,152 @@ BOOST_AUTO_TEST_CASE(Common_Value_TestCase_3)
   bool bool_values[] = {true, false, true, false};
   artis::common::event::Value bool_value{bool_values, 4};
   char char_values[] = {'a', 'b', 'c'};
-  artis::common::event::Value char_value{char_values, 3};
+  artis::common::event::Value char_value{char_values};
 
   BOOST_REQUIRE_EQUAL(int_value.to_string(), "1 2 3 ");
   BOOST_REQUIRE_EQUAL(unsigned_int_value.to_string(), "1 2 3 ");
-  BOOST_REQUIRE_EQUAL(double_value.to_string(), "0.500000 0.600000 1.200000 ");
+  BOOST_REQUIRE_EQUAL(double_value.to_string(), "0.5 0.6 1.2 ");
   BOOST_REQUIRE_EQUAL(bool_value.to_string(), "true false true false ");
   BOOST_REQUIRE_EQUAL(char_value.to_string(), "abc");
 }
 
 BOOST_AUTO_TEST_CASE(Common_Value_TestCase_4)
+{
+  std::vector<int> int_vector{1,2,3};
+  artis::common::event::Value int_values{int_vector};
+  std::vector<unsigned int> unsigned_int_vector{1, 2, 3};
+  artis::common::event::Value unsigned_int_values{unsigned_int_vector};
+  std::vector<double> double_vector{0.5, 0.6, 1.2};
+  artis::common::event::Value double_values{double_vector};
+  std::vector<bool> bool_vector{true, false, true, false};
+  artis::common::event::Value bool_values{bool_vector};
+  std::vector<char> char_vector{'a', 'b', 'c'};
+  artis::common::event::Value char_values{char_vector};
+
+  BOOST_REQUIRE_EQUAL(int_values.to_string(), "1 2 3 ");
+  BOOST_REQUIRE_EQUAL(unsigned_int_values.to_string(), "1 2 3 ");
+  BOOST_REQUIRE_EQUAL(double_values.to_string(), "0.5 0.6 1.2 ");
+  BOOST_REQUIRE_EQUAL(bool_values.to_string(), "true false true false ");
+  BOOST_REQUIRE_EQUAL(char_values.to_string(), "a b c ");
+}
+
+BOOST_AUTO_TEST_CASE(Common_Value_TestCase_5)
 {
   struct S {
+    std::string to_string() const { return "s"; }
+    bool operator==(const S& /* other */) const { return true; }
   } s;
   artis::common::event::Value value{s};
 
-  BOOST_REQUIRE_EQUAL(value.to_string(), "<unstringify>");
-}
+  BOOST_REQUIRE_EQUAL(value.to_string(), "s");
+}
+
+BOOST_AUTO_TEST_CASE(Common_Value_TestCase_6)
+{
+  struct S {
+    std::string to_string() const { return "s"; }
+    bool operator==(const S& /* other */) const { return true; }
+  };
+  std::vector<S> vs{S(), S(), S(), S()};
+  artis::common::event::Value value{vs};
+
+  BOOST_REQUIRE_EQUAL(value.to_string(), "s s s s ");
+}
+
+BOOST_AUTO_TEST_CASE(Common_Value_TestCase_7)
+{
+  artis::common::event::Value int_value{1};
+  artis::common::event::Value unsigned_int_value{(unsigned int) 1};
+  artis::common::event::Value double_value{0.5};
+  artis::common::event::Value bool_value{true};
+  artis::common::event::Value char_value{'a'};
+
+  int a;
+  unsigned int b;
+  double c;
+  bool d;
+  char e;
+
+  int_value(a);
+  unsigned_int_value(b);
+  double_value(c);
+  bool_value(d);
+  char_value(e);
+
+  BOOST_REQUIRE_EQUAL(a, 1);
+  BOOST_REQUIRE_EQUAL(b, 1);
+  BOOST_REQUIRE_EQUAL(c, 0.5);
+  BOOST_REQUIRE_EQUAL(d, true);
+  BOOST_REQUIRE_EQUAL(e, 'a');
+}
+
+BOOST_AUTO_TEST_CASE(Common_Value_TestCase_8)
+{
+  std::vector<int> int_vector{1,2,3};
+  artis::common::event::Value int_values{int_vector};
+  std::vector<unsigned int> unsigned_int_vector{1, 2, 3};
+  artis::common::event::Value unsigned_int_values{unsigned_int_vector};
+  std::vector<double> double_vector{0.5, 0.6, 1.2};
+  artis::common::event::Value double_values{double_vector};
+  std::vector<bool> bool_vector{true, false, true, false};
+  artis::common::event::Value bool_values{bool_vector};
+  std::vector<char> char_vector{'a', 'b', 'c'};
+  artis::common::event::Value char_values{char_vector};
+
+  std::vector<int> va;
+  std::vector<unsigned int> vb;
+  std::vector<double> vc;
+  std::vector<bool> vd;
+  std::vector<char> ve;
+
+  int_values(va);
+  unsigned_int_values(vb);
+  double_values(vc);
+  bool_values(vd);
+  char_values(ve);
+
+  BOOST_CHECK(std::equal(va.cbegin(), va.cend(), int_vector.cbegin()));
+  BOOST_CHECK(std::equal(vb.cbegin(), vb.cend(), unsigned_int_vector.cbegin()));
+  BOOST_CHECK(std::equal(vc.cbegin(), vc.cend(), double_vector.cbegin()));
+  BOOST_CHECK(std::equal(vd.cbegin(), vd.cend(), bool_vector.cbegin()));
+  BOOST_CHECK(std::equal(ve.cbegin(), ve.cend(), char_vector.cbegin()));
+}
+
+BOOST_AUTO_TEST_CASE(Common_Value_TestCase_9)
+{
+  struct S {
+    std::string to_string() const { return "s"; }
+    bool operator==(const S& /* other */) const { return true; }
+  };
+  S s;
+  artis::common::event::Value value{s};
+  S s2;
+
+  value(s2);
+  BOOST_CHECK(s == s2);
+}
+
+BOOST_AUTO_TEST_CASE(Common_Value_TestCase_10)
+{
+  struct S {
+    std::string to_string() const { return "s"; }
+    bool operator==(const S& /* other */) const { return true; }
+  };
+  std::vector<S> vs;
+  artis::common::event::Value value{vs};
+  std::vector<S> vs2;
+
+  value(vs2);
+  BOOST_CHECK(std::equal(vs.cbegin(), vs.cend(), vs2.cbegin()));
+}
+
+BOOST_AUTO_TEST_CASE(Common_Value_TestCase_11)
+{
+  std::string s{"artis"};
+  artis::common::event::Value value{s};
+  std::string s2;
+
+  value(s2);
+  BOOST_REQUIRE_EQUAL(value.to_string(), "artis");
+  BOOST_CHECK(s == s2);
+}