Skip to content

Commit

Permalink
Class template nlohmann::optional
Browse files Browse the repository at this point in the history
  • Loading branch information
karzhenkov committed Jun 21, 2022
1 parent 998a9d0 commit b7a5d99
Show file tree
Hide file tree
Showing 6 changed files with 616 additions and 45 deletions.
22 changes: 14 additions & 8 deletions include/nlohmann/detail/conversions/from_json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,14 @@
#include <utility> // pair, declval
#include <valarray> // valarray

#ifdef JSON_HAS_CPP_17
#if __has_include(<optional>)
#include <optional>
#elif __has_include(<experimental/optional>)
#include <experimental/optional>
#endif
#endif

#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/identity_tag.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/string_concat.hpp>
#include <nlohmann/detail/value_t.hpp>
#include <nlohmann/optional.hpp>

#if JSON_HAS_EXPERIMENTAL_FILESYSTEM
#include <experimental/filesystem>
Expand Down Expand Up @@ -69,6 +62,19 @@ void from_json(const BasicJsonType& j, std::optional<T>& opt)
opt = j.template get<T>();
}
}

template<typename BasicJsonType, typename T>
void from_json(const BasicJsonType& j, nlohmann::optional<T>& opt)
{
if (j.is_null())
{
opt = std::nullopt;
}
else
{
opt = j.template get<T>();
}
}
#endif

// overloads for basic_json template parameters
Expand Down
11 changes: 2 additions & 9 deletions include/nlohmann/detail/conversions/to_json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,11 @@
#include <vector> // vector

#include <nlohmann/detail/macro_scope.hpp>
#ifdef JSON_HAS_CPP_17
#if __has_include(<optional>)
#include <optional>
#elif __has_include(<experimental/optional>)
#include <experimental/optional>
#endif
#endif

#include <nlohmann/detail/iterators/iteration_proxy.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/value_t.hpp>
#include <nlohmann/optional.hpp>

#if JSON_HAS_EXPERIMENTAL_FILESYSTEM
#include <experimental/filesystem>
Expand Down Expand Up @@ -276,7 +269,7 @@ struct external_constructor<value_t::object>
#ifdef JSON_HAS_CPP_17
template<typename BasicJsonType, typename T,
enable_if_t<std::is_constructible<BasicJsonType, T>::value, int> = 0>
void to_json(BasicJsonType& j, const std::optional<T>& opt)
void to_json(BasicJsonType& j, const std::optional<T>& opt) noexcept
{
if (opt.has_value())
{
Expand Down
171 changes: 171 additions & 0 deletions include/nlohmann/optional.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#pragma once

#include <nlohmann/detail/macro_scope.hpp>

#ifdef JSON_HAS_CPP_17

#include <optional>
#include <utility>

namespace nlohmann
{

template <typename T>
class optional : public std::optional<T>
{
// *INDENT-OFF*

using base_type = std::optional<T>;

template <typename U, typename = optional>
struct has_conversion_operator : std::false_type { };

template <typename U>
struct has_conversion_operator<U,
decltype(std::declval<U>().operator optional())> : std::true_type { };

template <typename... U>
using is_base_constructible_from = std::is_constructible<base_type, U...>;

template <typename U>
using is_convertible_to_base = std::is_convertible<U, base_type>;

template <typename U>
using enable_int_if = std::enable_if_t<U::value, int>;

template <typename U>
using use_conversion_operator =
enable_int_if<
has_conversion_operator<U>
>;

template <typename U>
using use_implicit_forwarding =
enable_int_if<
std::conjunction<
std::negation<has_conversion_operator<U>>,
is_base_constructible_from<U>,
is_convertible_to_base<U>
>
>;

template <typename U>
using use_explicit_forwarding =
enable_int_if<
std::conjunction<
std::negation<has_conversion_operator<U>>,
is_base_constructible_from<U>,
std::negation<is_convertible_to_base<U>>
>
>;

template <typename... U>
using can_construct_in_place_from =
enable_int_if<
is_base_constructible_from<std::in_place_t, U...>
>;

public:

const base_type& base() const
{
return *this;
}

constexpr optional() noexcept = default;

constexpr optional(std::nullopt_t) noexcept
: base_type(std::nullopt)
{
}

template <typename U, use_conversion_operator<U> = 0>
constexpr optional(U&& value)
noexcept(noexcept(
base_type(std::forward<U>(value).operator optional())
)) :
base_type(std::forward<U>(value).operator optional())
{
}

template <typename U = T, use_implicit_forwarding<U> = 0>
constexpr optional(U&& value)
noexcept(noexcept(
base_type(std::forward<U>(value))
)) :
base_type(std::forward<U>(value))
{
}

template <typename U, use_explicit_forwarding<U> = 0>
explicit
constexpr optional(U&& value)
noexcept(noexcept(
base_type(std::forward<U>(value))
)) :
base_type(std::forward<U>(value))
{
}

template <typename U, typename... Args, can_construct_in_place_from<U, Args...> = 0>
explicit
constexpr optional(std::in_place_t, U&& u, Args&&... args)
noexcept(noexcept(
base_type(std::in_place, std::forward<U>(u), std::forward<Args>(args)...)
)) :
base_type(std::in_place, std::forward<U>(u), std::forward<Args>(args)...)
{
}

template <typename U, typename... Args, can_construct_in_place_from<std::initializer_list<U>&, Args...> = 0>
explicit
constexpr optional(std::in_place_t, std::initializer_list<U> u, Args&&... args)
noexcept(noexcept(
base_type(std::in_place, u, std::forward<Args>(args)...)
)) :
base_type(std::in_place, u, std::forward<Args>(args)...)
{
}

// *INDENT-ON*
};

template<class T, class U>
constexpr bool operator == (const optional<T>& lhs, const optional<U>& rhs)
{
return lhs.base() == rhs.base();
}

template<class T, class U>
constexpr bool operator != (const optional<T>& lhs, const optional<U>& rhs)
{
return lhs.base() != rhs.base();
}

template<class T, class U>
constexpr bool operator < (const optional<T>& lhs, const optional<U>& rhs)
{
return lhs.base() < rhs.base();
}

template<class T, class U>
constexpr bool operator <= (const optional<T>& lhs, const optional<U>& rhs)
{
return lhs.base() <= rhs.base();
}

template<class T, class U>
constexpr bool operator > (const optional<T>& lhs, const optional<U>& rhs)
{
return lhs.base() > rhs.base();
}

template<class T, class U>
constexpr bool operator >= (const optional<T>& lhs, const optional<U>& rhs)
{
return lhs.base() >= rhs.base();
}

} // namespace nlohmann

#endif // JSON_HAS_CPP_17
Loading

0 comments on commit b7a5d99

Please sign in to comment.