From f00898331e548e864b6d37f70c5470a841fe6cca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= <theo@tanker.io>
Date: Sun, 8 Jan 2017 14:06:25 +0100
Subject: [PATCH] replace constructor by from/to_json: number_integer_t

---
 src/json.hpp      | 129 +++++++++++-----------------------------------
 src/json.hpp.re2c | 129 +++++++++++-----------------------------------
 2 files changed, 62 insertions(+), 196 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index f3464894..9f8f3145 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -260,6 +260,18 @@ struct external_constructor<value_t::number_unsigned>
   }
 };
 
+template <>
+struct external_constructor<value_t::number_integer>
+{
+  template <typename Json>
+  static void construct(Json &j, typename Json::number_integer_t val) noexcept
+  {
+    j.m_type = value_t::number_integer;
+    j.m_value = val;
+    j.assert_invariant();
+  }
+};
+
 // very useful construct against boilerplate (more boilerplate needed than in
 // C++17: http://en.cppreference.com/w/cpp/types/void_t)
 template <typename...> struct make_void
@@ -387,6 +399,7 @@ struct is_compatible_integer_type_impl : std::false_type {};
 template <typename RealIntegerType, typename CompatibleNumberIntegerType>
 struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType>
 {
+  // is there an assert somewhere on overflows?
     using RealLimits = std::numeric_limits<RealIntegerType>;
     using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
 
@@ -402,7 +415,7 @@ struct is_compatible_integer_type
 {
   static constexpr auto
       value = is_compatible_integer_type_impl <
-                  std::is_arithmetic<CompatibleNumberIntegerType>::value and
+                  std::is_integral<CompatibleNumberIntegerType>::value and
               not std::is_same<bool, CompatibleNumberIntegerType>::value,
       RealIntegerType, CompatibleNumberIntegerType > ::value;
 };
@@ -422,8 +435,7 @@ struct is_compatible_basic_json_type
         is_unscoped_enum<T>::value or
         std::is_same<T, BasicJson>::value or
         is_compatible_array_type<BasicJson, T>::value or
-        is_compatible_object_type<typename BasicJson::object_t, T>::value or
-        is_compatible_integer_type<typename BasicJson::number_integer_t, T>::value;
+        is_compatible_object_type<typename BasicJson::object_t, T>::value;
 };
 
 template <typename T, typename BasicJson, typename PrimitiveIterator>
@@ -547,6 +559,16 @@ void to_json(Json &j, CompatibleNumberUnsignedType val) noexcept
   external_constructor<value_t::number_unsigned>::construct(j, val);
 }
 
+template <
+    typename Json, typename CompatibleNumberIntegerType,
+   enable_if_t<is_compatible_integer_type<typename Json::number_integer_t,
+                                         CompatibleNumberIntegerType>::value,
+                int> = 0>
+void to_json(Json &j, CompatibleNumberIntegerType val) noexcept
+{
+  external_constructor<value_t::number_integer>::construct(j, val);
+}
+
 template <typename Json>
 void from_json(Json const& j, typename Json::boolean_t& b)
 {
@@ -575,6 +597,12 @@ void from_json(Json const& j, typename Json::number_unsigned_t& val)
   get_arithmetic_value(j, val);
 }
 
+template <typename Json>
+void from_json(Json const& j, typename Json::number_integer_t& val)
+{
+  get_arithmetic_value(j, val);
+}
+
 // overload for arithmetic types, not chosen for basic_json template arguments (BooleanType, etc..)
 //
 // note: Is it really necessary to provide explicit overloads for boolean_t etc..
@@ -1820,64 +1848,6 @@ class basic_json
         JSONSerializer<uncvref_t<T>>::to_json(*this, std::forward<T>(val));
     }
 
-    /*!
-    @brief create an integer number (explicit)
-
-    Create an integer number JSON value with a given content.
-
-    @tparam T A helper type to remove this function via SFINAE in case @ref
-    number_integer_t is the same as `int`. In this case, this constructor
-    would have the same signature as @ref basic_json(const int value). Note
-    the helper type @a T is not visible in this constructor's interface.
-
-    @param[in] val  an integer to create a JSON number from
-
-    @complexity Constant.
-
-    @liveexample{The example below shows the construction of an integer
-    number value.,basic_json__number_integer_t}
-
-    @sa @ref basic_json(const int) -- create a number value (integer)
-    @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
-    value (integer) from a compatible number type
-
-    @since version 1.0.0
-    */
-    template<typename T, typename std::enable_if<
-                 not (std::is_same<T, int>::value) and
-                 std::is_same<T, number_integer_t>::value, int>::type = 0>
-    basic_json(const number_integer_t val) noexcept
-        : m_type(value_t::number_integer), m_value(val)
-    {
-        assert_invariant();
-    }
-
-    /*!
-    @brief create an integer number from an enum type (explicit)
-
-    Create an integer number JSON value with a given content.
-
-    @param[in] val  an integer to create a JSON number from
-
-    @note This constructor allows to pass enums directly to a constructor. As
-    C++ has no way of specifying the type of an anonymous enum explicitly, we
-    can only rely on the fact that such values implicitly convert to int. As
-    int may already be the same type of number_integer_t, we may need to
-    switch off the constructor @ref basic_json(const number_integer_t).
-
-    @complexity Constant.
-
-    @liveexample{The example below shows the construction of an integer
-    number value from an anonymous enum.,basic_json__const_int}
-
-    @sa @ref basic_json(const number_integer_t) -- create a number value
-    (integer)
-    @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
-    value (integer) from a compatible number type
-
-    @since version 1.0.0
-    */
-
     // Constructor for unscoped enums (not enum classes)
     template <typename T, enable_if_t<is_unscoped_enum<T>::value, int> = 0>
     basic_json(T val) noexcept
@@ -1887,43 +1857,6 @@ class basic_json
         assert_invariant();
     }
 
-    /*!
-    @brief create an integer number (implicit)
-
-    Create an integer number JSON value with a given content. This constructor
-    allows any type @a CompatibleNumberIntegerType that can be used to
-    construct values of type @ref number_integer_t.
-
-    @tparam CompatibleNumberIntegerType An integer type which is compatible to
-    @ref number_integer_t. Examples include the types `int`, `int32_t`,
-    `long`, and `short`.
-
-    @param[in] val  an integer to create a JSON number from
-
-    @complexity Constant.
-
-    @liveexample{The example below shows the construction of several integer
-    number values from compatible
-    types.,basic_json__CompatibleIntegerNumberType}
-
-    @sa @ref basic_json(const number_integer_t) -- create a number value
-    (integer)
-    @sa @ref basic_json(const int) -- create a number value (integer)
-
-    @since version 1.0.0
-    */
-    template <
-        typename CompatibleNumberIntegerType,
-        enable_if_t<detail::is_compatible_integer_type<
-                        number_integer_t, CompatibleNumberIntegerType>::value,
-                    int> = 0 >
-    basic_json(const CompatibleNumberIntegerType val) noexcept
-        : m_type(value_t::number_integer),
-          m_value(static_cast<number_integer_t>(val))
-    {
-        assert_invariant();
-    }
-
     /*!
     @brief create a container (array or object) from an initializer list
 
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index a7841f6f..909ce90d 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -260,6 +260,18 @@ struct external_constructor<value_t::number_unsigned>
   }
 };
 
+template <>
+struct external_constructor<value_t::number_integer>
+{
+  template <typename Json>
+  static void construct(Json &j, typename Json::number_integer_t val) noexcept
+  {
+    j.m_type = value_t::number_integer;
+    j.m_value = val;
+    j.assert_invariant();
+  }
+};
+
 // very useful construct against boilerplate (more boilerplate needed than in
 // C++17: http://en.cppreference.com/w/cpp/types/void_t)
 template <typename...> struct make_void
@@ -387,6 +399,7 @@ struct is_compatible_integer_type_impl : std::false_type {};
 template <typename RealIntegerType, typename CompatibleNumberIntegerType>
 struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType>
 {
+  // is there an assert somewhere on overflows?
     using RealLimits = std::numeric_limits<RealIntegerType>;
     using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
 
@@ -402,7 +415,7 @@ struct is_compatible_integer_type
 {
   static constexpr auto
       value = is_compatible_integer_type_impl <
-                  std::is_arithmetic<CompatibleNumberIntegerType>::value and
+                  std::is_integral<CompatibleNumberIntegerType>::value and
               not std::is_same<bool, CompatibleNumberIntegerType>::value,
       RealIntegerType, CompatibleNumberIntegerType > ::value;
 };
@@ -422,8 +435,7 @@ struct is_compatible_basic_json_type
         is_unscoped_enum<T>::value or
         std::is_same<T, BasicJson>::value or
         is_compatible_array_type<BasicJson, T>::value or
-        is_compatible_object_type<typename BasicJson::object_t, T>::value or
-        is_compatible_integer_type<typename BasicJson::number_integer_t, T>::value;
+        is_compatible_object_type<typename BasicJson::object_t, T>::value;
 };
 
 template <typename T, typename BasicJson, typename PrimitiveIterator>
@@ -547,6 +559,16 @@ void to_json(Json &j, CompatibleNumberUnsignedType val) noexcept
   external_constructor<value_t::number_unsigned>::construct(j, val);
 }
 
+template <
+    typename Json, typename CompatibleNumberIntegerType,
+   enable_if_t<is_compatible_integer_type<typename Json::number_integer_t,
+                                         CompatibleNumberIntegerType>::value,
+                int> = 0>
+void to_json(Json &j, CompatibleNumberIntegerType val) noexcept
+{
+  external_constructor<value_t::number_integer>::construct(j, val);
+}
+
 template <typename Json>
 void from_json(Json const& j, typename Json::boolean_t& b)
 {
@@ -575,6 +597,12 @@ void from_json(Json const& j, typename Json::number_unsigned_t& val)
   get_arithmetic_value(j, val);
 }
 
+template <typename Json>
+void from_json(Json const& j, typename Json::number_integer_t& val)
+{
+  get_arithmetic_value(j, val);
+}
+
 // overload for arithmetic types, not chosen for basic_json template arguments (BooleanType, etc..)
 //
 // note: Is it really necessary to provide explicit overloads for boolean_t etc..
@@ -1821,64 +1849,6 @@ class basic_json
         JSONSerializer<uncvref_t<T>>::to_json(*this, std::forward<T>(val));
     }
 
-    /*!
-    @brief create an integer number (explicit)
-
-    Create an integer number JSON value with a given content.
-
-    @tparam T A helper type to remove this function via SFINAE in case @ref
-    number_integer_t is the same as `int`. In this case, this constructor
-    would have the same signature as @ref basic_json(const int value). Note
-    the helper type @a T is not visible in this constructor's interface.
-
-    @param[in] val  an integer to create a JSON number from
-
-    @complexity Constant.
-
-    @liveexample{The example below shows the construction of an integer
-    number value.,basic_json__number_integer_t}
-
-    @sa @ref basic_json(const int) -- create a number value (integer)
-    @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
-    value (integer) from a compatible number type
-
-    @since version 1.0.0
-    */
-    template<typename T, typename std::enable_if<
-                 not (std::is_same<T, int>::value) and
-                 std::is_same<T, number_integer_t>::value, int>::type = 0>
-    basic_json(const number_integer_t val) noexcept
-        : m_type(value_t::number_integer), m_value(val)
-    {
-        assert_invariant();
-    }
-
-    /*!
-    @brief create an integer number from an enum type (explicit)
-
-    Create an integer number JSON value with a given content.
-
-    @param[in] val  an integer to create a JSON number from
-
-    @note This constructor allows to pass enums directly to a constructor. As
-    C++ has no way of specifying the type of an anonymous enum explicitly, we
-    can only rely on the fact that such values implicitly convert to int. As
-    int may already be the same type of number_integer_t, we may need to
-    switch off the constructor @ref basic_json(const number_integer_t).
-
-    @complexity Constant.
-
-    @liveexample{The example below shows the construction of an integer
-    number value from an anonymous enum.,basic_json__const_int}
-
-    @sa @ref basic_json(const number_integer_t) -- create a number value
-    (integer)
-    @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
-    value (integer) from a compatible number type
-
-    @since version 1.0.0
-    */
-
     // Constructor for unscoped enums (not enum classes)
     template <typename T, enable_if_t<is_unscoped_enum<T>::value, int> = 0>
     basic_json(T val) noexcept
@@ -1888,43 +1858,6 @@ class basic_json
         assert_invariant();
     }
 
-    /*!
-    @brief create an integer number (implicit)
-
-    Create an integer number JSON value with a given content. This constructor
-    allows any type @a CompatibleNumberIntegerType that can be used to
-    construct values of type @ref number_integer_t.
-
-    @tparam CompatibleNumberIntegerType An integer type which is compatible to
-    @ref number_integer_t. Examples include the types `int`, `int32_t`,
-    `long`, and `short`.
-
-    @param[in] val  an integer to create a JSON number from
-
-    @complexity Constant.
-
-    @liveexample{The example below shows the construction of several integer
-    number values from compatible
-    types.,basic_json__CompatibleIntegerNumberType}
-
-    @sa @ref basic_json(const number_integer_t) -- create a number value
-    (integer)
-    @sa @ref basic_json(const int) -- create a number value (integer)
-
-    @since version 1.0.0
-    */
-    template <
-        typename CompatibleNumberIntegerType,
-        enable_if_t<detail::is_compatible_integer_type<
-                        number_integer_t, CompatibleNumberIntegerType>::value,
-                    int> = 0 >
-    basic_json(const CompatibleNumberIntegerType val) noexcept
-        : m_type(value_t::number_integer),
-          m_value(static_cast<number_integer_t>(val))
-    {
-        assert_invariant();
-    }
-
     /*!
     @brief create a container (array or object) from an initializer list