<commit_before>#pragma once

#include "kl/type_class.hpp"
#include "kl/enum_reflector.hpp"
#include "kl/enum_flags.hpp"
#include "kl/tuple.hpp"
#include "kl/utility.hpp"

#include <boost/optional.hpp>
#include <json11/json11.hpp>
#include <exception>

KL_DEFINE_ENUM_REFLECTOR(json11, Json::Type,
                         (NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT))

namespace kl {

struct json_deserialize_error : std::exception
{
    explicit json_deserialize_error(const char* message)
        : json_deserialize_error(std::string(message))
    {
    }
    explicit json_deserialize_error(std::string message)
        : messages_(std::move(message))
    {
    }

    char const* what() const noexcept override { return messages_.c_str(); }

    void add(const char* message)
    {
        messages_.insert(end(messages_), '\n');
        messages_.append(message);
    }

private:
    std::string messages_;
};

// Forward declarations for top-level functions: to- and from- json conversions
template <typename T>
json11::Json to_json(const T& t);
template <typename T>
T from_json(const json11::Json& json);

namespace detail {

using ::kl::type_class::is_optional;
using ::kl::type_class::is_vector;
using ::kl::type_class::is_tuple;

// Checks if we can construct a Json object with given T
template <typename T>
using is_json_constructible =
    std::integral_constant<bool,
                           std::is_constructible<json11::Json, T>::value &&
                               // We want reflectable enum to handle ourselves
                               !std::is_enum<T>::value>;

template <typename T, typename = void_t<>>
struct is_string_associative : std::false_type {};
template <typename T>
struct is_string_associative<
    T, void_t<std::enable_if_t<
           type_class::equals<T, type_class::map>::value &&
           std::is_constructible<std::string, typename T::key_type>::value>>>
    : std::true_type {};

template <typename T>
using is_representable_as_double =
    std::integral_constant<bool,
                           std::is_integral<T>::value && (sizeof(T) <= 4)>;

template <typename T>
using is_enum_flags_reflectable = std::integral_constant<
    bool, is_enum_flags<T>::value &&
              is_enum_reflectable<typename T::enum_type>::value>;

struct json_factory
{
    // T is integral type with no more bytes than 4. Effectively, it's u32 as
    // all other cases are covered with is_json_constructible<T> 'true branch'
    template <typename T, enable_if<is_representable_as_double<T>> = true>
    static json11::Json create(const T& t)
    {
        if (static_cast<int>(t) >= 0)<commit_msg>Overload instead of using really odd SFINAE<commit_after>#pragma once

#include "kl/type_class.hpp"
#include "kl/enum_reflector.hpp"
#include "kl/enum_flags.hpp"
#include "kl/tuple.hpp"
#include "kl/utility.hpp"

#include <boost/optional.hpp>
#include <json11/json11.hpp>
#include <exception>

KL_DEFINE_ENUM_REFLECTOR(json11, Json::Type,
                         (NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT))

namespace kl {

struct json_deserialize_error : std::exception
{
    explicit json_deserialize_error(const char* message)
        : json_deserialize_error(std::string(message))
    {
    }
    explicit json_deserialize_error(std::string message)
        : messages_(std::move(message))
    {
    }

    char const* what() const noexcept override { return messages_.c_str(); }

    void add(const char* message)
    {
        messages_.insert(end(messages_), '\n');
        messages_.append(message);
    }

private:
    std::string messages_;
};

// Forward declarations for top-level functions: to- and from- json conversions
template <typename T>
json11::Json to_json(const T& t);
template <typename T>
T from_json(const json11::Json& json);

namespace detail {

using ::kl::type_class::is_optional;
using ::kl::type_class::is_vector;
using ::kl::type_class::is_tuple;

// Checks if we can construct a Json object with given T
template <typename T>
using is_json_constructible =
    std::integral_constant<bool,
                           std::is_constructible<json11::Json, T>::value &&
                               // We want reflectable enum to handle ourselves
                               !std::is_enum<T>::value>;

template <typename T, typename = void_t<>>
struct is_string_associative : std::false_type {};
template <typename T>
struct is_string_associative<
    T, void_t<std::enable_if_t<
           type_class::equals<T, type_class::map>::value &&
           std::is_constructible<std::string, typename T::key_type>::value>>>
    : std::true_type {};

template <typename T>
using is_enum_flags_reflectable = std::integral_constant<
    bool, is_enum_flags<T>::value &&
              is_enum_reflectable<typename T::enum_type>::value>;

struct json_factory
{
    // Overload for u32, which can safely be represented as json's Number
    // (double) value. All smaller unsigned types are handled in Json's
    // constructor as int.
    static json11::Json create(std::uint32_t t)
    {
        if (static_cast<int>(t) >= 0)
{'fraction_non_alphanumeric': 0.12148614114409279, 'fraction_numerical': 0.007470021623746805, 'mean_word_length': 3.538804638715433, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 56, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4596696', 'n_tokens_mistral': 1604, 'n_tokens_neox': 1560, 'n_words': 381}