Compare commits
3 Commits
54d9cd327a
...
933a36d992
Author | SHA1 | Date | |
---|---|---|---|
933a36d992 | |||
d3659f11f7 | |||
d207774868 |
122
source/mijin/util/formattable.hpp
Normal file
122
source/mijin/util/formattable.hpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef MIJIN_UTIL_FORMATTABLE_HPP_INCLUDED
|
||||||
|
#define MIJIN_UTIL_FORMATTABLE_HPP_INCLUDED 1
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include "../container/boxed_object.hpp"
|
||||||
|
|
||||||
|
namespace mijin
|
||||||
|
{
|
||||||
|
|
||||||
|
//
|
||||||
|
// public concepts
|
||||||
|
//
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept parse_result_type = requires
|
||||||
|
{
|
||||||
|
typename T::parse_result_t;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename TParseContext>
|
||||||
|
concept parseable_by_type = parse_result_type &&
|
||||||
|
requires(const T& object, TParseContext& parseContext)
|
||||||
|
{
|
||||||
|
{ T::parseFormat(parseContext) } -> std::convertible_to<std::pair<typename TParseContext::iterator, typename T::parse_result_t>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename TFmtContext>
|
||||||
|
concept simple_formattable_to_type = requires(const T& object, TFmtContext& formatContext)
|
||||||
|
{
|
||||||
|
{ object.format(formatContext) } -> std::convertible_to<typename TFmtContext::iterator>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename TFmtContext, typename TParseContext>
|
||||||
|
concept complex_formattable_to_type = parseable_by_type<T, TParseContext> &&
|
||||||
|
requires(const T& object, TParseContext& parseContext, TFmtContext& formatContext, T::parse_result_t& parseResult)
|
||||||
|
{
|
||||||
|
{ object.format(formatContext, parseResult) } -> std::convertible_to<typename TFmtContext::iterator>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename TFmtContext, typename TParseContext>
|
||||||
|
concept formattable_to_type = simple_formattable_to_type<T, TFmtContext> || complex_formattable_to_type<T, TFmtContext, TParseContext>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept cformattable_type = formattable_to_type<T, std::format_context, std::format_parse_context>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept wformattable_type = formattable_to_type<T, std::wformat_context, std::wformat_parse_context>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept formattable_type = cformattable_type<T> && wformattable_type<T>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept any_formattable_type = cformattable_type<T> || wformattable_type<T>;
|
||||||
|
|
||||||
|
//
|
||||||
|
// internal types
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace impl
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
struct ParseResult
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<parse_result_type T>
|
||||||
|
struct ParseResult<T>
|
||||||
|
{
|
||||||
|
BoxedObject<typename T::parse_result_t> value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} // namespace mijin
|
||||||
|
|
||||||
|
template<mijin::any_formattable_type T>
|
||||||
|
struct std::formatter<T>
|
||||||
|
{
|
||||||
|
[[no_unique_address]] [[maybe_unused]] mijin::impl::ParseResult<T> parseResult;
|
||||||
|
|
||||||
|
template<typename TContext>
|
||||||
|
constexpr TContext::iterator parse(TContext& ctx)
|
||||||
|
{
|
||||||
|
if constexpr (mijin::parse_result_type<T>)
|
||||||
|
{
|
||||||
|
static_assert(mijin::parseable_by_type<T, TContext>, "Type does not support parsing by this context.");
|
||||||
|
auto [it, result] = T::parseFormat(ctx);
|
||||||
|
parseResult.value.construct(std::move(result));
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto it = ctx.begin();
|
||||||
|
auto end = ctx.end();
|
||||||
|
|
||||||
|
if (it != end && *it != '}')
|
||||||
|
{
|
||||||
|
throw std::format_error("invalid format");
|
||||||
|
}
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TContext>
|
||||||
|
TContext::iterator format(const T& object, TContext& ctx) const
|
||||||
|
{
|
||||||
|
if constexpr (mijin::parse_result_type<T>)
|
||||||
|
{
|
||||||
|
auto it = object.format(ctx, std::move(*parseResult.value));
|
||||||
|
parseResult.destroy();
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static_assert(mijin::simple_formattable_to_type<T, TContext>, "Type does not support formatting to this context.");
|
||||||
|
return object.format(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // MIJIN_UTIL_FORMATTABLE_HPP_INCLUDED
|
@ -3,6 +3,7 @@
|
|||||||
#if !defined(MIJIN_UTIL_ITERATORS_HPP_INCLUDED)
|
#if !defined(MIJIN_UTIL_ITERATORS_HPP_INCLUDED)
|
||||||
#define MIJIN_UTIL_ITERATORS_HPP_INCLUDED 1
|
#define MIJIN_UTIL_ITERATORS_HPP_INCLUDED 1
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -39,9 +39,9 @@ namespace mijin
|
|||||||
// internal variables
|
// internal variables
|
||||||
//
|
//
|
||||||
|
|
||||||
#if MIJIN_TARGET_OS == MIJIN_OS_LINUX
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
#if MIJIN_TARGET_OS == MIJIN_OS_LINUX
|
||||||
std::mutex gDlErrorMutex; // dlerror may not be thread-safe
|
std::mutex gDlErrorMutex; // dlerror may not be thread-safe
|
||||||
|
|
||||||
const std::uint64_t gCPUClockResolution = []()
|
const std::uint64_t gCPUClockResolution = []()
|
||||||
@ -52,8 +52,16 @@ const std::uint64_t gCPUClockResolution = []()
|
|||||||
MIJIN_ASSERT(time.tv_sec == 0, "What kind of cpu clock is this?");
|
MIJIN_ASSERT(time.tv_sec == 0, "What kind of cpu clock is this?");
|
||||||
return static_cast<std::uint64_t>(time.tv_nsec);
|
return static_cast<std::uint64_t>(time.tv_nsec);
|
||||||
}();
|
}();
|
||||||
};
|
#elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
|
||||||
#endif // MIJIN_TARGET_OS == MIJIN_OS_LINUX
|
const std::uint64_t gCPUTickFrequency = []()
|
||||||
|
{
|
||||||
|
LARGE_INTEGER ticks;
|
||||||
|
[[maybe_unused]] const BOOL result = QueryPerformanceFrequency(&ticks);
|
||||||
|
MIJIN_ASSERT(result, "Error getting cpu frequency.");
|
||||||
|
return static_cast<std::uint64_t>(ticks.QuadPart);
|
||||||
|
}();
|
||||||
|
#endif // MIJIN_TARGET_OS == MIJIN_OS_LINUX || MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// internal functions
|
// internal functions
|
||||||
@ -196,8 +204,10 @@ std::uint64_t getCPUTicks() MIJIN_NOEXCEPT
|
|||||||
MIJIN_ASSERT(result == 0, "Error getting cpu time.");
|
MIJIN_ASSERT(result == 0, "Error getting cpu time.");
|
||||||
return (static_cast<std::uint64_t>(time.tv_sec) * 1e9 + time.tv_nsec) / gCPUClockResolution;
|
return (static_cast<std::uint64_t>(time.tv_sec) * 1e9 + time.tv_nsec) / gCPUClockResolution;
|
||||||
#else
|
#else
|
||||||
MIJIN_ERROR("TODO");
|
LARGE_INTEGER ticks;
|
||||||
return 0;
|
[[maybe_unused]] const BOOL result = QueryPerformanceCounter(&ticks);
|
||||||
|
MIJIN_ASSERT(result, "Error getting cpu time.");
|
||||||
|
return static_cast<std::uint64_t>(ticks.QuadPart);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,8 +216,7 @@ std::uint64_t getCPUTicksPerSecond() MIJIN_NOEXCEPT
|
|||||||
#if MIJIN_TARGET_OS == MIJIN_OS_LINUX
|
#if MIJIN_TARGET_OS == MIJIN_OS_LINUX
|
||||||
return 1e9 / gCPUClockResolution;
|
return 1e9 / gCPUClockResolution;
|
||||||
#else
|
#else
|
||||||
MIJIN_ERROR("TODO");
|
return gCPUTickFrequency;
|
||||||
return 0;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace mijin
|
} // namespace mijin
|
||||||
|
Loading…
x
Reference in New Issue
Block a user