<commit_before>#pragma once
#include <typeinfo>
#include <gsl/gsl_assert>
#include <algorithm>
#include "halleystring.h"
#include <halley/support/exception.h>
#include <array>

namespace Halley
{

	template <typename T>
	struct EnumNames {
	};


	
	struct UserConverter
	{
		template<typename T>
		static String toString(const T& v)
		{
			if constexpr (std::is_enum<T>::value) {
				return EnumNames<T>()()[int(v)];
			} else {
				return v.toString();
			}
		}

		template<typename T>
		static T fromString(const String& str)
		{
			if constexpr (std::is_enum<T>::value) {
				EnumNames<T> n;
				auto names = n();
				auto res = std::find_if(std::begin(names), std::end(names), [&](const char* v) { return str == v; });
				if (res == std::end(names)) {
					throw Exception("String \"" + str + "\" does not exist in enum \"" + typeid(T).name() + "\".", HalleyExceptions::Utils);
				}
				return T(res - std::begin(names));
			} else {
				return T(str);
			}
		}
	};


	template <typename T>
	struct ToStringConverter {
		String operator()(const T& s) const
		{
			return UserConverter::toString(s);
		}
	};

	template <typename T>
	struct FromStringConverter {
		T operator()(const String& s) const
		{
			return UserConverter::fromString<T>(s);
		}
	};

	template<size_t N>
	struct ToStringConverter<char[N]>
	{
		String operator()(const char s[N]) const
		{
			return String(s);
		}
	};
	
	template<>
	struct ToStringConverter<const char*>
	{
		String operator()(const char* s) const
		{
			return String(s);
		}
	};

	template<>
	struct ToStringConverter<char*>
	{
		String operator()(const char* s) const
		{
			return String(s);
		}
	};

	template<size_t N>
	struct ToStringConverter<wchar_t[N]>
	{
		String operator()(const wchar_t s[N]) const
		{
			return String(s);
		}
	};

	template<>
	struct ToStringConverter<const wchar_t*>
	{
		String operator()(const wchar_t* s) const
		{
			return String(s);
		}
	};

	template<>
	struct ToStringConverter<wchar_t*>
	{
		String operator()(const wchar_t* s) const
		{
			return String(s);
		}
	};

	template<>
	struct ToStringConverter<std::string>
	{
		String operator()(const std::string& s) const
		{
			return String(s);
		}
	};

	template<>
	struct ToStringConverter<bool>
	{
		String operator()(bool s) const
		{
			return String(s ? "true" : "false");
		}
	};

	template<>
	struct FromStringConverter<bool>
	{
		bool operator()(const String& s) const
		{
			return s == "true";
		}
	};

	
	template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
	String toString(T src, int precisionDigits = -1, char decimalSeparator = '.')
	{
		Expects(precisionDigits >= -1 && precisionDigits <= 20);<commit_msg>Allow converting std::optional<T> to String<commit_after>#pragma once
#include <typeinfo>
#include <gsl/gsl_assert>
#include <algorithm>
#include "halleystring.h"
#include <halley/support/exception.h>
#include <array>
#include <optional>

namespace Halley
{

	template <typename T>
	struct EnumNames {
	};


	
	struct UserConverter
	{
		template<typename T>
		static String toString(const T& v)
		{
			if constexpr (std::is_enum<T>::value) {
				return EnumNames<T>()()[int(v)];
			} else {
				return v.toString();
			}
		}

		template<typename T>
		static T fromString(const String& str)
		{
			if constexpr (std::is_enum<T>::value) {
				EnumNames<T> n;
				auto names = n();
				auto res = std::find_if(std::begin(names), std::end(names), [&](const char* v) { return str == v; });
				if (res == std::end(names)) {
					throw Exception("String \"" + str + "\" does not exist in enum \"" + typeid(T).name() + "\".", HalleyExceptions::Utils);
				}
				return T(res - std::begin(names));
			} else {
				return T(str);
			}
		}
	};


	template <typename T>
	struct ToStringConverter {
		String operator()(const T& s) const
		{
			return UserConverter::toString(s);
		}
	};

	template <typename T>
	struct FromStringConverter {
		T operator()(const String& s) const
		{
			return UserConverter::fromString<T>(s);
		}
	};

	template<size_t N>
	struct ToStringConverter<char[N]>
	{
		String operator()(const char s[N]) const
		{
			return String(s);
		}
	};
	
	template<>
	struct ToStringConverter<const char*>
	{
		String operator()(const char* s) const
		{
			return String(s);
		}
	};

	template<>
	struct ToStringConverter<char*>
	{
		String operator()(const char* s) const
		{
			return String(s);
		}
	};

	template<size_t N>
	struct ToStringConverter<wchar_t[N]>
	{
		String operator()(const wchar_t s[N]) const
		{
			return String(s);
		}
	};

	template<>
	struct ToStringConverter<const wchar_t*>
	{
		String operator()(const wchar_t* s) const
		{
			return String(s);
		}
	};

	template<>
	struct ToStringConverter<wchar_t*>
	{
		String operator()(const wchar_t* s) const
		{
			return String(s);
		}
	};

	template<>
	struct ToStringConverter<std::string>
	{
		String operator()(const std::string& s) const
		{
			return String(s);
		}
	};

	template<>
	struct ToStringConverter<bool>
	{
		String operator()(bool s) const
		{
			return String(s ? "true" : "false");
		}
	};

	template<>
	struct FromStringConverter<bool>
	{
		bool operator()(const String& s) const
		{
			return s == "true";
		}
	};

	template<typename T>
	struct ToStringConverter<std::optional<T>>
	{
		String operator()(const std::optional<T>& v) const
		{
			if (v) {
				return toString(v.value());
			} else {
				return "{}";
			}
		}
	};

	
	template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
	String toString(T src, int precisionDigits = -1, char decimalSeparator = '.')
	{
		Expects(precisionDigits >= -1 && precisionDigits <= 20);
{'fraction_non_alphanumeric': 0.15710503089143865, 'fraction_numerical': 0.00176522506619594, 'mean_word_length': 3.6826446280991734, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 83, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2764831', 'n_tokens_mistral': 2305, 'n_tokens_neox': 2018, 'n_words': 462}