/**
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