/** This file is a part of rexy's general purpose library Copyright (C) 2022 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef REXY_DETAIL_FORMAT_FORMAT_ARGS_TPP #define REXY_DETAIL_FORMAT_FORMAT_ARGS_TPP #include "format_args.hpp" #include "basic_types.hpp" //format_string_view #include "standard_types.hpp" #include "parse_context.hpp" #include "format_context.hpp" #include "storage.hpp" #include "arg_store.hpp" #include "format_error.hpp" #include "../../string_view.hpp" #include //forward #include //remove_cvref, add_lvalue_reference, add_pointer, add_const, conditional #include //size_t #include //addressof namespace rexy::fmt{ /////////////////////////////basic_format_arg::handle////////////////////////////// template template basic_format_arg::handle::handle(T&& t): m_data(std::addressof(t)), m_format_impl(&handle::format_impl>){} template template void basic_format_arg::handle::format_impl(basic_format_parse_context& parse_ctx, Context& format_ctx)const{ using value_type = std::remove_cvref_t; using formatter_t = typename Context::template formatter_type; using qualified_type = std::conditional_t, std::add_const_t, value_type>; using reference_type = std::add_lvalue_reference_t; using pointer_type = std::add_pointer_t; using const_pointer_type = std::add_pointer_t>; reference_type ref = *const_cast(reinterpret_cast(m_data)); formatter_t fmt; parse_ctx.advance_to(fmt.parse(parse_ctx)); format_ctx.advance_to(fmt.format(ref, format_ctx)); } template void basic_format_arg::handle::format(basic_format_parse_context& parse_ctx, Context& format_ctx)const{ //Pretty epic gamer moment here (this->*m_format_impl)(parse_ctx, format_ctx); } ///////////////////////////////basic_format_arg//////////////////////////////// template basic_format_arg::basic_format_arg(bool b)noexcept: bool_v(b), active_member(detail::storage_type::bool_t){} template basic_format_arg::basic_format_arg(char_type b)noexcept: char_v(b), active_member(detail::storage_type::char_t){} template basic_format_arg::basic_format_arg(int b)noexcept: int_v(b), active_member(detail::storage_type::int_t){} template basic_format_arg::basic_format_arg(unsigned int b)noexcept: uint_v(b), active_member(detail::storage_type::uint_t){} template basic_format_arg::basic_format_arg(long long b)noexcept: long_long_v(b), active_member(detail::storage_type::long_long_t){} template basic_format_arg::basic_format_arg(unsigned long long b)noexcept: ulong_long_v(b), active_member(detail::storage_type::ulong_long_t){} template basic_format_arg::basic_format_arg(float b)noexcept: float_v(b), active_member(detail::storage_type::float_t){} template basic_format_arg::basic_format_arg(double b)noexcept: double_v(b), active_member(detail::storage_type::double_t){} template basic_format_arg::basic_format_arg(long double b)noexcept: long_double_v(b), active_member(detail::storage_type::long_double_t){} template basic_format_arg::basic_format_arg(const char_type* b)noexcept: char_ptr_v(b), active_member(detail::storage_type::char_ptr_t){} template basic_format_arg::basic_format_arg(basic_string_view b)noexcept: string_v(b), active_member(detail::storage_type::string_t){} template basic_format_arg::basic_format_arg(const void* b)noexcept: ptr_v(b), active_member(detail::storage_type::ptr_t){} template basic_format_arg::basic_format_arg(const handle b)noexcept: custom_v(b), active_member(detail::storage_type::custom_t){} template detail::storage_type basic_format_arg::type(void)const{ return active_member; } template basic_format_arg::operator bool(void)const noexcept{ return active_member != detail::storage_type::none_t; } ///////////////////////////////basic_format_args//////////////////////////////// template constexpr basic_format_args::basic_format_args(const detail::basic_format_arg_store&)noexcept{} template template basic_format_args::basic_format_args(const detail::basic_format_arg_store& store)noexcept: m_info(store.packed_data.info()), m_data(store.packed_data.data()), m_num_args(sizeof...(Args)){} template basic_format_arg basic_format_args::get(std::size_t i)const noexcept{ const bool named = m_info[i].named; const std::size_t offset = m_info[i].offset + (named ? sizeof(detail::format_string_view) : 0); const unsigned char* const data = m_data + offset; switch(m_info[i].type){ case detail::storage_type::bool_t: return basic_format_arg{*reinterpret_cast(data)}; case detail::storage_type::char_t: return basic_format_arg{*reinterpret_cast(data)}; case detail::storage_type::int_t: return basic_format_arg{*reinterpret_cast(data)}; case detail::storage_type::uint_t: return basic_format_arg{*reinterpret_cast(data)}; case detail::storage_type::long_long_t: return basic_format_arg{*reinterpret_cast(data)}; case detail::storage_type::ulong_long_t: return basic_format_arg{*reinterpret_cast(data)}; case detail::storage_type::float_t: return basic_format_arg{*reinterpret_cast(data)}; case detail::storage_type::double_t: return basic_format_arg{*reinterpret_cast(data)}; case detail::storage_type::long_double_t: return basic_format_arg{*reinterpret_cast(data)}; case detail::storage_type::char_ptr_t: return basic_format_arg{*reinterpret_cast(data)}; case detail::storage_type::string_t: return basic_format_arg{*reinterpret_cast*>(data)}; case detail::storage_type::ptr_t: return basic_format_arg{reinterpret_cast(*reinterpret_cast(data))}; case detail::storage_type::custom_t: return basic_format_arg{*reinterpret_cast::handle*>(data)}; default: return basic_format_arg{}; }; } template basic_format_arg basic_format_args::get(const char_type* first, const char_type* last)const{ return get(get_index(first, last)); } template std::size_t basic_format_args::get_index(const char_type* first, const char_type* last)const{ for(std::size_t i = 0;i < m_num_args;++i){ if(m_info[i].named){ auto data = reinterpret_cast* const>(m_data + m_info[i].offset); const std::size_t len = last - first; if(len == data->length && !rexy::strncmp(data->name, first, len)){ return i; } } } REXY_THROW_FORMAT_ERROR("Requested named arg does not exist"); } template decltype(auto) visit_format_arg(Fun&& fun, const basic_format_arg& arg){ switch(arg.type()){ case detail::storage_type::bool_t: return std::forward(fun)(arg.bool_v); case detail::storage_type::char_t: return std::forward(fun)(arg.char_v); case detail::storage_type::int_t: return std::forward(fun)(arg.int_v); case detail::storage_type::uint_t: return std::forward(fun)(arg.uint_v); case detail::storage_type::long_long_t: return std::forward(fun)(arg.long_long_v); case detail::storage_type::ulong_long_t: return std::forward(fun)(arg.ulong_long_v); case detail::storage_type::float_t: return std::forward(fun)(arg.float_v); case detail::storage_type::double_t: return std::forward(fun)(arg.double_v); case detail::storage_type::long_double_t: return std::forward(fun)(arg.long_double_v); case detail::storage_type::char_ptr_t: return std::forward(fun)(arg.char_ptr_v); case detail::storage_type::string_t: return std::forward(fun)(arg.string_v); case detail::storage_type::ptr_t: return std::forward(fun)(arg.ptr_v); case detail::storage_type::custom_t: return std::forward(fun)(arg.custom_v); default: REXY_THROW_FORMAT_ERROR("Invalid format_arg storage_type"); }; } } #endif