Skip to content

Commit

Permalink
feat: variant
Browse files Browse the repository at this point in the history
  • Loading branch information
neko-para committed Feb 16, 2025
1 parent ae3ea2f commit e820d42
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 8 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,6 @@ package.json
package-lock.json
yarn.lock
pnpm-lock.yaml

# Clangd
.cache
60 changes: 60 additions & 0 deletions include/common/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>

namespace json
{
Expand Down Expand Up @@ -84,6 +86,11 @@ constexpr bool is_collection = false;
template <typename T>
constexpr bool is_collection<T> = is_container<T> && !is_map<T> && !is_fixed_array<T>;

template <typename T>
constexpr bool is_variant = false;
template <typename... args_t>
constexpr bool is_variant<std::variant<args_t...>> = true;

template <typename T>
class has_to_json_in_member
{
Expand Down Expand Up @@ -261,4 +268,57 @@ inline string_t to_basic_string(any_t&& arg)
static_assert(!sizeof(any_t), "Unsupported type");
}
}

template <std::size_t id, typename string_t, typename variant_t>
bool serialize_variant_impl(basic_value<string_t>& val, variant_t&& var)
{
if (var.index() == id) {
val = basic_value<string_t>(std::get<id>(std::forward<variant_t>(var)));
return false;
}
return true;
}

template <typename string_t, typename variant_t, std::size_t... ids>
basic_value<string_t> serialize_variant(variant_t&& var, std::index_sequence<ids...>)
{
basic_value<string_t> val;
(serialize_variant_impl<ids>(val, std::forward<variant_t>(var)) && ...);
return val;
}

template <std::size_t id, typename string_t, typename variant_t>
bool deserialize_variant_impl(const basic_value<string_t>& val, variant_t& var)
{
using alt_t = std::variant_alternative_t<id, variant_t>;
if (val.template is<alt_t>()) {
var = val.template as<alt_t>();
return false;
}
return true;
}

template <typename string_t, typename variant_t, std::size_t... ids>
variant_t deserialize_variant(const basic_value<string_t>& val, std::index_sequence<ids...>)
{
variant_t var;
(deserialize_variant_impl<ids>(val, var) && ...);
return var;
}

template <typename string_t, typename alt_t>
bool detect_variant_impl(const basic_value<string_t>& val)
{
if (val.template is<alt_t>()) {
return true;
}
return false;
}

template <typename string_t, typename variant_t, std::size_t... ids>
bool detect_variant(const basic_value<string_t>& val, std::index_sequence<ids...>)
{
return (detect_variant_impl<string_t, std::variant_alternative_t<ids, variant_t>>(val) && ...);
}

} // namespace json::_utils
39 changes: 32 additions & 7 deletions include/common/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <ostream>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <variant>

#include "exception.hpp"
Expand Down Expand Up @@ -134,6 +136,16 @@ class basic_value
{
}

template <
typename variant_t,
std::enable_if_t<_utils::is_variant<std::remove_reference_t<variant_t>>, bool> = true>
basic_value(variant_t&& var)
: basic_value(_utils::serialize_variant<string_t>(
std::forward<variant_t>(var),
std::make_index_sequence<std::variant_size_v<std::remove_reference_t<variant_t>>>()))
{
}

template <
typename value_t,
std::enable_if_t<!std::is_convertible_v<value_t, basic_value<string_t>>, bool> = true>
Expand Down Expand Up @@ -366,13 +378,21 @@ class basic_value
{
return as_array().template as_tuple<elem_ts...>();
}

template <typename elem1_t, typename elem2_t>
explicit operator std::pair<elem1_t, elem2_t>() const
{
return as_array().template as_pair<elem1_t, elem2_t>();
}

template <typename... args_t>
explicit operator std::variant<args_t...>() const
{
return _utils::deserialize_variant<string_t, std::variant<args_t...>>(
*this,
std::make_index_sequence<std::variant_size_v<std::variant<args_t...>>>());
}

private:
friend class basic_array<string_t>;
friend class basic_object<string_t>;
Expand Down Expand Up @@ -566,6 +586,11 @@ inline bool basic_value<string_t>::is() const noexcept
return is_object() && std::is_constructible_v<string_t, typename value_t::key_type>
&& all<typename value_t::mapped_type>();
}
else if constexpr (_utils::is_variant<value_t>) {
return _utils::detect_variant<string_t, value_t>(
*this,
std::make_index_sequence<std::variant_size_v<value_t>>());
}
else {
static_assert(!sizeof(value_t), "Unsupported type");
}
Expand Down Expand Up @@ -637,16 +662,16 @@ inline auto basic_value<string_t>::get_helper(
{
if constexpr (std::is_constructible_v<string_t, first_key_t>) {
return is_object() ? as_object().get_helper(
default_value,
std::forward<first_key_t>(first),
std::forward<rest_keys_t>(rest)...)
default_value,
std::forward<first_key_t>(first),
std::forward<rest_keys_t>(rest)...)
: default_value;
}
else if constexpr (std::is_integral_v<std::decay_t<first_key_t>>) {
return is_array() ? as_array().get_helper(
default_value,
std::forward<first_key_t>(first),
std::forward<rest_keys_t>(rest)...)
default_value,
std::forward<first_key_t>(first),
std::forward<rest_keys_t>(rest)...)
: default_value;
}
else {
Expand Down
7 changes: 6 additions & 1 deletion test/serializing_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@

bool serializing()
{
std::variant<int, std::vector<int>> var = 1;
json::value k = var;
auto var2 = k.as<std::variant<int, std::vector<int>>>();
auto is_var = k.is<std::variant<int, std::vector<int>>>();

json::value root;

root["hello"] = "meojson";
Expand Down Expand Up @@ -286,7 +291,7 @@ bool jsonizing()
mine.w = MyStruct::W::C;

json::value j_mine = mine;
std::cout << j_mine<< std::endl;
std::cout << j_mine << std::endl;

MyStruct new_mine = (MyStruct)j_mine;

Expand Down

0 comments on commit e820d42

Please sign in to comment.