WhiZTiM / UbjsonCpp

A high performance C++14 library for effortlessly reading and writing UBJSON
24 stars 11 forks source link

Doesn't build or work at all on MSVC #12

Closed mlfarrell closed 6 years ago

mlfarrell commented 6 years ago

I thought this was supposed to be a portable library.

mlfarrell commented 6 years ago

I took a sledgehammer to this problem today. I have no idea if I broke anything yet. But at least it builds.

Patch attached below. Paths won't be correct so I didn't make a PR

You may want to stop using " or " "and " and " not " in place of && || and !. Honestly, I have absolutely no idea how that ever compiled correctly in the first place.

From 70faf0f7843efa50b08e6bbbdfb7e0bf1d89a2a3 Mon Sep 17 00:00:00 2001
From: Mike Farrell <@gmail.com>
Date: Wed, 18 Jul 2018 17:53:09 -0700
Subject: [PATCH] - get the UbjsonCpp lib to build on MSVC (regression risks,
 here, will need to test again on iOS)

---
 .../UbjsonCpp/include/Ubjson/portable_endian.h     |  38 +-
 .../UbjsonCpp/include/Ubjson/stream_helpers.hpp    |   2 +-
 .../UbjsonCpp/include/Ubjson/stream_reader.hpp     |  18 +-
 .../UbjsonCpp/include/Ubjson/stream_writer.hpp     |  16 +-
 .../3rd Party/UbjsonCpp/include/Ubjson/types.hpp   |   9 +-
 .../3rd Party/UbjsonCpp/include/Ubjson/value.cpp   | 936 +++++++++++++++++++++
 .../3rd Party/UbjsonCpp/include/Ubjson/value.hpp   |   2 +-
 7 files changed, 998 insertions(+), 23 deletions(-)
 create mode 100644 BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/value.cpp

diff --git a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/portable_endian.h b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/portable_endian.h
index 05f8861..3364d75 100644
--- a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/portable_endian.h  
+++ b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/portable_endian.h  
@@ -74,8 +74,11 @@

 #elif defined(__WINDOWS__)

-#  include <winsock2.h>
+#  include <Winsock2.h>
+#ifndef _MSC_VER
 #  include <sys/param.h>
+#else
+#endif

 #  if BYTE_ORDER == LITTLE_ENDIAN

@@ -89,10 +92,43 @@
 #      define be32toh(x) ntohl(x)
 #      define le32toh(x) (x)

+//these simply will...not...work..
+#ifdef _MSC_VER
+uint64_t ___ntohll(uint64_t x)
+{
+  uint32_t x0, x1, y0, y1;
+
+  if(ntohl(1) == 1) 
+  {
+    return x;
+  }
+
+  x0 = x & 0xffffffff;
+  y0 = ntohl(x0);
+  x1 = x >> 32;
+  y1 = ntohl(x1);
+  return ((uint64_t)y0 << 32) | y1;
+}
+
+uint64_t ___htonll(uint64_t n)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+  return n;
+#else
+  return (((uint64_t)htonl(n)) << 32) + htonl(n >> 32);
+#endif
+}
+
+#      define htobe64(x) ___htonll(x)
+#      define htole64(x) (x)
+#      define be64toh(x) ___ntohll(x)
+#      define le64toh(x) (x)
+#else
 #      define htobe64(x) htonll(x)
 #      define htole64(x) (x)
 #      define be64toh(x) ntohll(x)
 #      define le64toh(x) (x)
+#endif

 #  elif BYTE_ORDER == BIG_ENDIAN

diff --git a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_helpers.hpp b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_helpers.hpp
index 6e0be52..74e61d5 100755
--- a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_helpers.hpp 
+++ b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_helpers.hpp 
@@ -37,7 +37,7 @@ namespace ubjson {
     }

     inline bool in_range(double value, double min, double max)
-    { return (min <= value and value <= max); }
+    { return (min <= value && value <= max); }

    inline
     uint16_t toBigEndian16(uint16_t val)
diff --git a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_reader.hpp b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_reader.hpp
index b8e3ab5..3a06a94 100755
--- a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_reader.hpp  
+++ b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_reader.hpp  
@@ -89,7 +89,7 @@ namespace ubjson {
         std::enable_if_t<std::is_base_of<std::istream, U>::value, bool> read_from_stream(byte*, std::size_t, bool peek = false);

         template<typename U = StreamType>
-        std::enable_if_t<not std::is_base_of<std::istream, U>::value, bool> read_from_stream(byte*, std::size_t, bool peek = false);
+        std::enable_if_t<! std::is_base_of<std::istream, U>::value, bool> read_from_stream(byte*, std::size_t, bool peek = false);
         //decltype(std::declval<U>().peek(), std::true_type()()) read_from_stream(byte*, std::size_t);

         std::pair<byte, bool> peeked_byte;
@@ -179,7 +179,7 @@ namespace ubjson {

     template<typename StreamType>
-    template<typename U> std::enable_if_t<not std::is_base_of<std::istream, U>::value, bool>
+    template<typename U> std::enable_if_t<! std::is_base_of<std::istream, U>::value, bool>
     StreamReader<StreamType>::read_from_stream(byte* b, std::size_t sz, bool peek)
     {
         using std::to_string;
@@ -190,7 +190,7 @@ namespace ubjson {
             if(bytes_so_far + sz > vsz.max_object_size)
                 throw policy_violation("Maximum Object size read at: " + to_string(bytes_so_far));

-            if(peek and peeked_byte.second)
+            if(peek && peeked_byte.second)
             {
                 b[0] = peeked_byte.first;
                 b = b + 1;
@@ -223,9 +223,9 @@ namespace ubjson {

         decltype(KeyMarker::marker) marker;
         KeyMarker km;
-        while ( (not header.is_valid) or (header.is_valid and header.item_count > 0)) {
+        while ( (! header.is_valid) || (header.is_valid && header.item_count > 0)) {

-            if(not header.is_valid and is_container_end(type, peekNextByte()))
+            if(! header.is_valid && is_container_end(type, peekNextByte()))
             {
                 readNextByte(); //peel it off the stream
                 break;
@@ -246,7 +246,7 @@ namespace ubjson {
                 break;
             }

-            if(header.marker != Marker::Invalid and header.is_valid)
+            if(header.marker != Marker::Invalid && header.is_valid)
                 marker = km.marker;
             else
                 marker = readNextByte();
@@ -428,7 +428,7 @@ namespace ubjson {
     {
         byte b = readNextByte();

-        if(isUint8(b) and read_uint8)
+        if(isUint8(b) && read_uint8)
         {
             auto rtn = extract_Uint8();
             return std::make_pair(rtn.first, rtn.second);
@@ -491,7 +491,7 @@ namespace ubjson {
     std::pair<std::string, bool> StreamReader<StreamType>::extract_String()
     {
         auto icount = extract_itemCount();
-        if(not icount.second)
+        if(!icount.second)
             return std::make_pair(std::string(), false);

         std::unique_ptr<byte[]> b(new byte[icount.first]);
@@ -505,7 +505,7 @@ namespace ubjson {
     std::pair<Value::BinaryType, bool> StreamReader<StreamType>::extract_Binary()
     {
         auto icount = extract_itemCount();
-        if(not icount.second)
+        if(!icount.second)
             throw parsing_exception("Invalid count token encounted!");

         std::unique_ptr<byte[]> b(new byte[icount.first]);
diff --git a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_writer.hpp b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_writer.hpp
index a20596c..3f3a0b3 100755
--- a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_writer.hpp  
+++ b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/stream_writer.hpp  
@@ -240,8 +240,8 @@ namespace ubjson {
         else if(in_range(val, Int16::lowest(), Int16::max()))
         {
             const uint16_t tit = static_cast<uint16_t>(val);
-            const uint16_t val = toBigEndian16(tit);
-            std::memcpy(b, &val, 2);
+            const uint16_t temp = toBigEndian16(tit);
+            std::memcpy(b, &temp, 2);
             write(Marker::Int16);
             write(b, 2);
             rtn = std::make_pair(3, true);
@@ -249,8 +249,8 @@ namespace ubjson {
         else if(in_range(val, Int32::lowest(), Int32::max()))
         {
             const uint32_t tit = static_cast<uint32_t>(val);
-            const uint32_t val = toBigEndian32(tit);
-            std::memcpy(b, &val, 4);
+            const uint32_t temp = toBigEndian32(tit);
+            std::memcpy(b, &temp, 4);
             write(Marker::Int32);
             write(b, 4);
             rtn = std::make_pair(5, true);
@@ -258,8 +258,8 @@ namespace ubjson {
         else if(in_range(val, Int64::lowest(), Int64::max()))
         {
             const uint64_t tit = static_cast<uint64_t>(val);
-            const uint64_t val = toBigEndian64(tit);
-            std::memcpy(b, &val, 8);
+            const uint64_t temp = toBigEndian64(tit);
+            std::memcpy(b, &temp, 8);
             write(Marker::Int64);
             write(b, 8);
             rtn = std::make_pair(9, true);
@@ -282,8 +282,8 @@ namespace ubjson {
             //const uint32_t val = toBigEndianFloat32(static_cast<float>(val));

             float temp = static_cast<float>(val);           //Walkaround
-            const uint32_t val = toBigEndianFloat32(temp);  //Walkaround
-            std::memcpy(b, &val, 4);
+            const uint32_t temp2 = toBigEndianFloat32(temp);  //Walkaround
+            std::memcpy(b, &temp2, 4);
             write(Marker::Float32);
             write(b, 4);
             rtn = std::make_pair(5, true);
diff --git a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/types.hpp b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/types.hpp
index 2fbc57e..42b8db0 100755
--- a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/types.hpp  
+++ b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/types.hpp  
@@ -101,7 +101,8 @@ namespace ubjson {

     constexpr bool isSignedNumber(byte b)
-    { return isInt16(b) or isInt32(b) or isInt64(b);  }
+    { return isInt16(b) || isInt32(b) || isInt64(b); }
+    //{ return isInt16(b) or isInt32(b) or isInt64(b);  }

     constexpr bool isNumber(byte b)
     { return isSignedNumber(b);  }
@@ -128,10 +129,12 @@ namespace ubjson {
     { return b == Marker::Optimized_Count; }

     constexpr bool isOptimizedMarker(byte b)
-    { return isOptimized_Count(b) or isOptimized_Type(b); }
+    { return isOptimized_Count(b) || isOptimized_Type(b); }
+    //{ return isOptimized_Count(b) or isOptimized_Type(b); }

     constexpr bool requiresPayload(byte b)
-    { return isObjectStart(b) or isString(b) or isBinary(b) or isArrayStart(b); }
+    { return isObjectStart(b) || isString(b) || isBinary(b) || isArrayStart(b); }
+    //{ return isObjectStart(b) or isString(b) or isBinary(b) or isArrayStart(b); }

     static_assert(sizeof(byte) == 1, "a byte must be exactly one byte(8 bits)");

diff --git a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/value.cpp b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/value.cpp
new file mode 100644
index 0000000..992b71c
--- /dev/null
+++ b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/value.cpp  
@@ -0,0 +1,936 @@
+#include "pch.h"
+
+/*
+ * Copyright(C):    WhiZTiM, 2015
+ *
+ * This file is part of the TIML::UBJSON C++14 library
+ *
+ * Distributed under the Boost Software License, Version 1.0.
+ *      (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Author: Ibrahim Timothy Onogu
+ * Email:  ionogu@acm.org
+ */
+
+
+#include "value.hpp"
+#include <cmath>
+#include <limits>
+#include <cstring>
+#include <algorithm>
+#include <iostream>
+
+using namespace ubjson;
+
+/////////////////  FREE FUNCTIONS
+template<typename T>
+T unique_ptr_copy(const T& src);
+
+template<>
+inline Value::ArrayType unique_ptr_copy(const Value::ArrayType& src)
+{
+    Value::ArrayType rtn;
+    for(auto& v : src)
+        rtn.emplace_back( std::make_unique<Value>(*v) );
+    rtn.shrink_to_fit();
+    return rtn;
+}
+
+template<>
+inline Value::MapType unique_ptr_copy(const Value::MapType& src)
+{
+    Value::MapType rtn;
+    for(auto& v : src)
+        rtn.emplace( std::make_pair(v.first, std::make_unique<Value>(*(v.second)) ));
+    return rtn;
+}
+
+inline bool in_range(double value, double min, double max)
+{ return (min <= value && value <= max); }
+
+inline bool is_equal(const Value::MapType& lhs, const Value::MapType& rhs)
+{
+    if(lhs.size() != rhs.size())    //edge case
+        return false;
+
+    for(const auto& val : lhs)
+    {
+        if(rhs.find(val.first) == rhs.end())
+            return false;
+        if(! (*(lhs.at(val.first)) == *(rhs.at(val.first))))
+            return false;
+    }
+    return true;
+}
+
+inline bool is_equal(const Value::ArrayType& lhs, const Value::ArrayType& rhs)
+{
+    return std::equal(lhs.begin(), lhs.end(),
+                      rhs.begin(), rhs.end(),
+                      []( const Value::Uptr& lhss, const Value::Uptr& rhss )
+                        { return *lhss == *rhss; }
+                     );
+}
+
+//////////////// VALUE IMpl
+
+
+Value::Value()
+    : vtype(Type::Null)
+{ }
+
+Value::Value(char c)
+    : vtype(Type::Char)
+{  value.Char = c; }
+
+Value::Value(bool b)
+    : vtype(Type::Bool)
+{  value.Bool = b; }
+
+Value::Value(long long ll)
+    : vtype(Type::SignedInt)
+{  value.SignedInt = ll; }
+
+Value::Value(int i)
+    : Value(static_cast<long long>(i))
+{  /**/ }
+
+Value::Value(unsigned long long ull)
+    : vtype(Type::UnsignedInt)
+{  value.UnsignedInt = ull; }
+
+Value::Value(double d)
+    : vtype(Type::Float)
+{  value.Float = d; }
+
+Value::Value(BinaryType b)
+    : vtype(Type::Binary)
+{   construct_fromBinary(std::move(b)); }
+
+Value::Value(std::string s)
+    : vtype(Type::String)
+{   construct_fromString(std::move(s)); }
+
+Value::Value(const char* c)
+    : Value(std::string(c))
+{  /**/  }
+
+Value::Value(std::initializer_list<Value> v)
+    : Value()   //I suffered a setback here... explanation below
+{
+    if(v.size() == 1)
+    {
+        copy_from(*v.begin());
+        return;
+    }
+    for(auto a : v)
+        push_back( std::move(a) );
+// The bug was the fact that I didn't call the default constructor( basically initializes vtype=Type::Null)
+// Thus, the move was failing in optimized builds
+// Lesson: learn to use in-class default construction to maintain a first-class construction invariant
+}
+
+Value::Value(const std::string& key, Value val)
+    : Value()
+{
+    operator[](key) = val;
+}
+
+
+Value::Value(Value&& v)
+    : Value()
+{   move_from(std::move(v)); }
+
+Value::Value(const Value& v)
+    : Value()
+{   copy_from(v); }
+
+
+Value& Value::operator = (const Value& v)
+{
+    if(this == &v)
+        return *this;
+    copy_from(v);
+    return *this;
+}
+
+Value& Value::operator = (Value&& v)
+{
+    move_from(std::move(v));
+    return *this;
+}
+
+
+Value::~Value()
+{
+    destruct();
+}
+
+size_t Value::size() const noexcept
+{
+    switch (vtype) {
+    case Type::Null:
+        return 0;
+    case Type::Array:
+        return value.Array.size();
+    case Type::Map:
+        return value.Map.size();
+    default:
+        return 1;
+    }
+}
+
+Type Value::type() const noexcept
+{ return vtype; }
+
+Value& Value::operator [] (int i)
+{
+    if(vtype == Type::Array)
+        return *(value.Array[i]);
+    throw value_exception("Attempt to index 'Value'; 'Value' is not an Array!");
+}
+
+Value const& Value::operator [] (int i) const
+{
+    if(vtype == Type::Array)
+        return *(value.Array[i]);
+    throw value_exception("Attempt to index 'Value const&'; 'Value const&' is not an Array!");
+}
+
+Value& Value::operator [] (const std::string& s)
+{
+    if(vtype == Type::Map)
+    {
+        if(value.Map.find(s) == value.Map.end())
+            value.Map.emplace( std::make_pair(s, std::make_unique<Value>(Value())));
+        return *(value.Map[s]);
+    }
+    if(vtype == Type::Null)
+    {
+        // convert to Map
+        destruct();
+        construct_fromMap(MapType());
+        vtype = Type::Map;
+        value.Map.emplace( std::make_pair(s, std::make_unique<Value>(Value())));
+        return *(value.Map[s]);
+    }
+    throw value_exception("Attempt to index 'Value'; 'Value' is not a Key-Value pair (aka Object) !");
+}
+
+Value const& Value::operator [] (const std::string& s) const
+{
+    if(vtype == Type::Map)
+        return *(const_cast<const MapType&>(value.Map).at(s));
+    throw value_exception("Attempt to index 'Value const&'; 'Value const&' is not a Key-Value pair (aka Object) !");
+}
+
+Value& Value::operator [] (const char* c)
+{ return operator [] (std::string(c)); }
+
+Value const& Value::operator [] (const char* c) const
+{ return operator [] (std::string(c)); }
+
+void Value::push_back(Value&& v)
+{
+    switch (vtype) {
+    case Type::Null:
+        construct_fromArray(ArrayType());
+        vtype = Type::Array;
+    case Type::Array:
+        value.Array.emplace_back( std::make_unique<Value>( std::move(v) ) );
+        break;
+    default:
+    {
+        Value tmp(std::move(*this));
+        construct_fromArray(ArrayType());
+        value.Array.emplace_back(std::make_unique<Value>( std::move(tmp) ));
+        value.Array.emplace_back(std::make_unique<Value>( std::move(v) ));
+        vtype = Type::Array;
+        break;
+    }
+
+    }
+}
+
+void Value::push_back(const Value& v)
+{
+    switch (vtype) {
+    case Type::Null:
+        construct_fromArray(ArrayType());
+        vtype = Type::Array;
+    case Type::Array:
+        value.Array.emplace_back( std::make_unique<Value>(v) );
+        break;
+    default:
+    {
+        Value tmp(std::move(*this));
+        construct_fromArray(ArrayType());
+        value.Array.emplace_back(std::make_unique<Value>( std::move(tmp) ));
+        value.Array.emplace_back(std::make_unique<Value>( v ));
+        vtype = Type::Array;
+        break;
+    }
+
+    }
+}
+
+void Value::remove(const Value& v)
+{
+    switch (vtype) {
+    case Type::Array:
+    {
+        auto it = std::find_if(value.Array.begin(), value.Array.end(),
+                     [&v](const auto& m){ return v == *m; } );
+        if(it != value.Array.end() )
+            value.Array.erase(it);
+        break;
+    }
+    case Type::Map:
+        value.Map.erase(v.asString());
+    default:
+        break;
+    }
+}
+
+Value::iterator Value::find(const Value& v)
+{
+    switch (vtype) {
+    case Type::Array:
+    {
+        auto it = std::find_if(value.Array.begin(), value.Array.end(),
+                     [&v](const auto& m){ return v == *m; } );
+        if(it == value.Array.end() )
+            return end();
+        return iterator(this, it);
+    }
+    case Type::Map:
+    {
+        auto it = value.Map.find(v.asString());
+        if(it == value.Map.end())
+            return end();
+        return iterator(this, it);
+    }
+    default:
+        break;
+    }
+    return end();
+}
+
+
+Value::const_iterator Value::find(const Value& v) const
+{
+    switch (vtype) {
+    case Type::Array:
+    {
+        auto it = std::find_if(value.Array.begin(), value.Array.end(),
+                     [&v](const auto& m){ return v == *m; } );
+        if(it == value.Array.end() )
+            return end();
+        return const_iterator(this, it);
+    }
+    case Type::Map:
+    {
+        auto it = value.Map.find(v);
+        if(it == value.Map.end())
+            return end();
+        return const_iterator(this, it);
+    }
+    default:
+        break;
+    }
+    return end();
+}
+
+bool Value::contains(const Value& v) const
+{ return find(v) != end(); }
+
+Value::Keys Value::keys() const
+{
+    if(! isMap())
+        return Keys();
+
+    Keys rtn;
+    for(const auto& k : value.Map)
+        rtn.push_back( k.first );
+    return rtn;
+}
+
+bool Value::isNull()    const noexcept { return vtype == Type::Null;   }
+bool Value::isArray()   const noexcept { return vtype == Type::Array;  }
+bool Value::isBinary()  const noexcept { return vtype == Type::Binary; }
+bool Value::isBool()    const noexcept { return vtype == Type::Bool;   }
+bool Value::isChar()    const noexcept { return vtype == Type::Char;   }
+bool Value::isFloat()   const noexcept { return vtype == Type::Float;  }
+bool Value::isMap()     const noexcept { return vtype == Type::Map;    }
+bool Value::isString()  const noexcept { return vtype == Type::String; }
+bool Value::isSignedInteger()   const noexcept { return vtype == Type::SignedInt;   }
+bool Value::isUnsignedInteger() const noexcept { return vtype == Type::UnsignedInt; }
+bool Value::isObject()  const noexcept  { return isMap();                       }
+bool Value::isNumeric()  const noexcept { return isInteger() || isFloat();     }
+bool Value::isInteger() const noexcept  { return isSignedInteger() || isUnsignedInteger(); }
+
+bool Value::isComparableWith(const Value &rhs) const noexcept
+{
+    if(type() == rhs.type())
+        return true;
+    return (isNumeric() && rhs.isNumeric());
+}
+
+
+//////////////// as<...> functions //////
+///
+///
+//////////////////////////
+
+long long Value::asInt64() const noexcept
+{
+    using limit = std::numeric_limits<long long>;
+
+    if(isSignedInteger())
+        return value.SignedInt;
+    if(isUnsignedInteger())
+        return in_range(value.UnsignedInt, limit::lowest(), limit::max()) ? value.UnsignedInt : 0;
+    if(isFloat())
+        return in_range(value.Float, limit::lowest(), limit::max()) ? value.Float : 0;
+
+    if(isChar())
+        return static_cast<long long>(value.Char);
+    if(isBool())
+        return value.Bool ? 1 : 0;
+    if(isString())
+    {
+        try { return std::stoll(value.String); }
+        catch (std::invalid_argument&) {}
+        catch (std::out_of_range&) {}
+        return 0;
+    }
+    return size();
+}
+
+
+unsigned long long Value::asUint64() const noexcept
+{
+    using limit = std::numeric_limits<unsigned long long>;
+
+    if(isUnsignedInteger())
+        return value.UnsignedInt;
+    if(isSignedInteger())
+        return in_range(value.SignedInt, limit::lowest(), limit::max()) ? value.SignedInt : 0;
+    if(isFloat())
+        return in_range(value.Float, limit::lowest(), limit::max()) ? value.Float : 0;
+    if(isChar())
+        return static_cast<unsigned long long>(value.Char);
+    if(isBool())
+        return value.Bool ? 1 : 0;
+    if(isString())
+    {
+        try { return std::stoull(value.String); }
+        catch (std::invalid_argument&) {}
+        catch (std::out_of_range&) {}
+        return 0;
+    }
+
+    return size();
+}
+
+double Value::asFloat() const noexcept
+{
+
+    if(isFloat())
+        return value.Float;
+    if(isString())
+    {
+        try { return std::stod(value.String); }
+        catch (std::invalid_argument&) {}
+        catch (std::out_of_range&) {}
+        return 0;
+    }
+
+    double k1 = asUint64();
+    double k2 = asInt64();
+
+    return k1 > k2 ? k1 : k2;
+}
+
+bool Value::asBool() const noexcept
+{
+    if(isBool())
+        return value.Bool;
+    if(isUnsignedInteger())
+        return value.UnsignedInt != 0;
+    if(isSignedInteger())
+        return value.SignedInt != 0;
+    if(isFloat())
+        return value.Float != 0;
+    if(isChar())
+        return value.Char != '\0';
+    return size() != 0;
+}
+
+int Value::asInt() const noexcept
+{
+    using limit = std::numeric_limits<int>;
+    return in_range(asInt64(), limit::lowest(), limit::max()) ? (int)asInt64() : 0;
+}
+
+unsigned int Value::asUint() const noexcept
+{
+    using limit = std::numeric_limits<unsigned int>;
+    return in_range(asUint64(), limit::lowest(), limit::max()) ? (unsigned int)asUint64() : 0;
+}
+
+std::string Value::asString() const noexcept
+{
+    if(isString())
+        return value.String;
+    if(isBool())
+        return value.Bool ? "true" : "false";
+    // if(isBinary())
+        //What should we do for Binary? Base64? or what?
+    if(isChar())
+        return {value.Char};
+    if(isSignedInteger())
+        return std::to_string(value.SignedInt);
+    if(isUnsignedInteger())
+        return std::to_string(value.UnsignedInt);
+    if(isFloat())
+        return std::to_string(value.Float);
+    return "";
+}
+
+inline Value::BinaryType as_binary(const void* src, size_t size)
+{
+    Value::BinaryType rtn(size);
+    std::memcpy(&rtn[0], src, size);
+    return rtn;
+}
+
+Value::BinaryType Value::asBinary() const noexcept
+{
+    if(isBinary())
+        return value.Binary;
+    switch (vtype) {
+    case Type::Char:
+        return as_binary(&value.Char, sizeof(value.Char));
+    case Type::Bool:
+        return as_binary(&value.Bool, sizeof(value.Bool));
+    case Type::SignedInt:
+        return as_binary(&value.SignedInt, sizeof(value.SignedInt));
+    case Type::UnsignedInt:
+        return as_binary(&value.UnsignedInt, sizeof(value.UnsignedInt));
+    case Type::Float:
+        return as_binary(&value.Float, sizeof(value.Float));
+    case Type::String:
+        //return as_binary(reinterpret_cast<byte*>(value.String), sizeof(value.Char));
+    case Type::Array:
+        //return as_binary(reinterpret_cast<byte*>(value.Array), sizeof(value.Array));
+    case Type::Map:
+        //return as_binary(reinterpret_cast<byte*>(value.Map), sizeof(value.Map));
+    case Type::Binary:
+    default:
+        break;
+    }
+    return Value::BinaryType();
+}
+
+//////////////// PRIVATE ////////////////
+/////////////////////////////////////////
+///
+///
+///
+/////////////////////////////////////////
+
+
+void Value::construct_fromString(std::string&& s)
+{
+    new( &(value.String)) std::string(std::move(s));
+}
+
+void Value::construct_fromBinary(BinaryType&& b)
+{
+    new( &(value.Binary)) BinaryType(std::move(b));
+}
+
+void Value::construct_fromArray(ArrayType&& a)
+{
+    new( &(value.Array)) ArrayType(std::move(a));
+}
+
+void Value::construct_fromMap(MapType&& m)
+{
+    new( &(value.Map)) MapType(std::move(m));
+}
+
+void Value::move_from(Value&& v)
+{
+    destruct();
+
+    switch (v.vtype) {
+    case Type::Char:
+        value.Char = v.value.Char;
+        break;
+    case Type::Bool:
+        value.Bool = v.value.Bool;
+        break;
+    case Type::SignedInt:
+        value.SignedInt = v.value.SignedInt;
+        break;
+    case Type::UnsignedInt:
+        value.UnsignedInt = v.value.UnsignedInt;
+        break;
+    case Type::Float:
+        value.Float = v.value.Float;
+        break;
+    case Type::String:
+        construct_fromString( std::move(v.value.String) );
+        break;
+    case Type::Binary:
+        construct_fromBinary( std::move(v.value.Binary) );
+        break;
+    case Type::Array:
+        construct_fromArray(  std::move(v.value.Array)  );
+        break;
+    case Type::Map:
+        construct_fromMap(    std::move(v.value.Map)    );
+        break;
+    default:
+        break;
+    }
+
+    vtype = v.vtype;
+    v.destruct();
+}
+
+void Value::copy_from(const Value& v)
+{
+    destruct();
+
+    switch (v.vtype) {
+    case Type::Char:
+        value.Char = v.value.Char;
+        break;
+    case Type::Bool:
+        value.Bool = v.value.Bool;
+        break;
+    case Type::SignedInt:
+        value.SignedInt = v.value.SignedInt;
+        break;
+    case Type::UnsignedInt:
+        value.UnsignedInt = v.value.UnsignedInt;
+        break;
+    case Type::Float:
+        value.Float = v.value.Float;
+        break;
+    case Type::String:
+        construct_fromString( std::string( v.value.String ));
+        break;
+    case Type::Binary:
+        construct_fromBinary( BinaryType(  v.value.Binary ));
+        break;
+    case Type::Array:
+        construct_fromArray( ArrayType(unique_ptr_copy(v.value.Array)));
+        break;
+    case Type::Map:
+        construct_fromMap( MapType(unique_ptr_copy(v.value.Map)));
+        break;
+    default:
+        break;
+    }
+    vtype = v.vtype;
+}
+
+inline void Value::destruct() noexcept
+{
+    using std::string;
+    using std::vector;
+
+
+    switch (vtype) {
+    case Type::Null:
+        return;
+    case Type::String:
+        value.String.~string();
+        break;
+    case Type::Array:
+        value.Array.~vector();
+        break;
+    case Type::Binary:
+        value.Binary.~vector();
+        break;
+    case Type::Map:
+        value.Map.~unordered_map();
+        break;
+    default:
+        break;
+    }
+
+    vtype = Type::Null;
+    //std::cout << "d " << std::flush;
+}
+
+
+//////////////////////////  CONVERSION OPERATOR  ///////////////////////////
+///// I currently don't know a better way to avoid code duplication here
+///// C++ forbids a const function to call a none const function
+
+
+///simple int
+Value::operator int ()
+{ return int( operator long long& () ); }
+Value::operator int () const
+{ return int( operator long long const& () ); }
+
+
+///// long long
+Value::operator long long& () &
+{
+    if(vtype == Type::SignedInt)
+        return value.SignedInt;
+    throw bad_value_cast("'Value&' cannot be casted to 'long long'");
+}
+
+Value::operator long long const& () const&
+{
+    if(vtype == Type::SignedInt)
+        return value.SignedInt;
+    throw bad_value_cast("'Value const&' cannot casted to 'long long'");
+}
+
+
+///// unsigned long long
+Value::operator unsigned long long& () &
+{
+    if(vtype == Type::UnsignedInt)
+        return value.UnsignedInt;
+    throw bad_value_cast("'Value&' cannot be casted to 'unsigned long long'");
+}
+
+Value::operator unsigned long long const& () const&
+{
+    if(vtype == Type::UnsignedInt)
+        return value.UnsignedInt;
+    throw bad_value_cast("'Value const&' cannot be casted to 'unsigned long long'");
+}
+
+
+///// bool
+Value::operator bool & () &
+{
+    if(vtype == Type::Bool)
+        return value.Bool;
+    throw bad_value_cast("'Value&' cannot be casted to 'bool'");
+}
+
+Value::operator bool const& () const&
+{
+    if(vtype == Type::Bool)
+        return value.Bool;
+    throw bad_value_cast("'Value const&' cannot be casted to 'bool'");
+}
+
+
+///// char
+Value::operator char & () &
+{
+    if(vtype == Type::Char)
+        return value.Char;
+    throw bad_value_cast("'Value&' cannot be casted to 'char'");
+}
+
+Value::operator char const& () const&
+{
+    if(vtype == Type::Char)
+        return value.Char;
+    throw bad_value_cast("'Value const&' cannot be casted to 'char'");
+}
+
+
+///// double
+Value::operator double & () &
+{
+    if(vtype == Type::Float)
+        return value.Float;
+    throw bad_value_cast("'Value&' cannot be casted to 'double'");
+}
+
+Value::operator double const& () const&
+{
+    if(vtype == Type::Float)
+        return value.Float;
+    throw bad_value_cast("'Value&' cannot be casted to 'double'");
+}
+
+
+///// std::string
+Value::operator std::string&& () &&
+{
+    if(vtype == Type::String)
+        return std::move(value.String);
+    throw bad_value_cast("'Value&&' cannot be casted to 'std::string&&'");
+}
+
+Value::operator std::string& () &
+{
+    if(vtype == Type::String)
+        return value.String;
+    throw bad_value_cast("'Value&' cannot be casted to 'std::string&'");
+}
+
+Value::operator std::string const& () const&
+{
+    if(vtype == Type::String)
+        return value.String;
+    throw bad_value_cast("'Value const&' cannot be casted to 'std::string const&'");
+}
+
+
+///// BinaryType
+Value::operator BinaryType&& () &&
+{
+    if(vtype == Type::Binary)
+        return std::move(value.Binary);
+    throw bad_value_cast("'Value&&' cannot be casted to 'BinaryType&&'");
+}
+
+Value::operator BinaryType& () &
+{
+    if(vtype == Type::Binary)
+        return value.Binary;
+    throw bad_value_cast("'Value&' cannot be casted to 'BinaryType&'");
+}
+
+Value::operator BinaryType const& () const&
+{
+    if(vtype == Type::Binary)
+        return value.Binary;
+    throw bad_value_cast("'Value const&' cannot be casted to 'BinaryType const&'");
+}
+
+
+//////////////////////// FRIEND FUNCTION ///////////
+
+void ubjson::swap(Value& v1, Value& v2)
+{
+    Value vt;
+    vt.move_from( std::move( v2 ));
+    v2.move_from( std::move( v1 ));
+    v1.move_from( std::move( vt ));
+}
+
+/////////////////////// FREE OPERATORS ////////////
+
+bool ubjson::operator == (const Value& lhs, const Value& rhs)
+{
+    using limit = std::numeric_limits<double>;
+
+    if(lhs.isNumeric() && rhs.isNumeric())
+        return std::abs(lhs.asFloat() - rhs.asFloat()) <= limit::epsilon();
+
+    if(lhs.type() != rhs.type())
+        return false;
+
+    switch (rhs.type()) {
+    case Type::Null:
+        return true;
+    case Type::Char:
+        return lhs.value.Char == rhs.value.Char;
+    case Type::Bool:
+        return lhs.value.Bool == rhs.value.Bool;
+    case Type::String:
+        return lhs.value.String == rhs.value.String;
+    case Type::Binary:
+        return lhs.value.Binary == rhs.value.Binary;
+    case Type::Array:
+        return is_equal(lhs.value.Array, rhs.value.Array);
+    case Type::Map:
+        return is_equal(lhs.value.Map, rhs.value.Map);
+    default:
+        break;
+    }
+    return false;
+}
+
+bool ubjson::operator != (const Value& lhs, const Value& rhs)
+{ 
+   return ! ubjson::operator == (lhs, rhs); 
+}
+
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///
+
+///////////////////////////////////////////////////////////
+
+
+std::ostream& ubjson::operator << (std::ostream& os, to_ostream&& tos)
+{
+    tos.print_value(os, tos.value);
+    return os;
+}
+
+void to_ostream::print_object(std::ostream &os, const Value &v)
+{
+    os << '{' << (ppretty ? "\n" : "");
+    if(ppretty)
+        push_addendum('\t');
+
+    const auto keys = v.keys();
+
+    size_t idx = 0, idxEnd = keys.size();
+    for(const auto& key : keys)
+    {
+        os << addendum << "\"" << key << "\"" << (ppretty ? " : " : ":");;
+        print_value(os, v[key]);
+
+        if(++idx < idxEnd)
+            os << ',';
+        os << (ppretty ? "\n" : "");
+    }
+
+    pop_addendum();
+    os << addendum << '}';
+}
+
+void to_ostream::print_array(std::ostream &os, const Value &v)
+{
+    if(ppretty)
+        push_addendum('\t');
+    os << '[';
+
+    for(size_t i=0; i < v.size(); i++)
+    {
+        print_value(os, v[(int)i]);
+
+        if(i + 1 < v.size())
+            os << (ppretty ? ", " : ",");
+    }
+
+    pop_addendum();
+    os << ']';
+}
+
+void to_ostream::print_value(std::ostream &os, const Value &v)
+{
+    if(v.isNull())
+        os << "null";
+    else if(v.isBool())
+        os << (v ? "true" : "false");
+    else if(v.isChar())
+        os << "\"" << static_cast<char>(v) << "\"";
+    else if(v.isSignedInteger())
+        os << static_cast<long long>(v);
+    else if(v.isUnsignedInteger())
+        os << static_cast<unsigned long long>(v);
+    else if(v.isFloat())
+        os << static_cast<double>(v);
+    else if(v.isString())
+        os << "\"" << static_cast<std::string>(v) << "\"";
+    else if(v.isBinary())
+        os << "BINARY DATA (" << static_cast<const Value::BinaryType&>(v).size() << " bytes)";
+    else if(v.isArray())
+        print_array(os, v);
+    else if(v.isObject())
+        print_object(os, v);
+}
diff --git a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/value.hpp b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/value.hpp
index 39a236f..5553b34 100755
--- a/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/value.hpp  
+++ b/BGModeler/BGModeler/src/3rd Party/UbjsonCpp/include/Ubjson/value.hpp  
@@ -552,7 +552,7 @@ namespace ubjson {
         { addendum.push_back(c); }

         inline void pop_addendum() {
-            if(not addendum.empty())
+            if(! addendum.empty())
                 addendum.pop_back();
         }

-- 
2.9.0.windows.1
WhiZTiM commented 6 years ago

Thanks for this observation @mlfarrell , I honestly didn't test it on MSVC as of the time of release and wrongly assumed MSVC will support alternative operators;

Thanks for the patch, I'll use it to fix up the library this weekend.

WhiZTiM commented 6 years ago

Fixed: https://github.com/WhiZTiM/UbjsonCpp/tree/a915f1bf65f7f7d778bd4151a864fda9294c6ae4