237 lines
9.5 KiB
C++
237 lines
9.5 KiB
C++
/**
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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 <utility> //forward
|
|
#include <type_traits> //remove_cvref, add_lvalue_reference, add_pointer, add_const, conditional
|
|
#include <cstddef> //size_t
|
|
#include <memory> //addressof
|
|
|
|
namespace rexy::fmt{
|
|
|
|
/////////////////////////////basic_format_arg::handle//////////////////////////////
|
|
template<class Context>
|
|
template<class T>
|
|
basic_format_arg<Context>::handle::handle(T&& t):
|
|
m_data(std::addressof(t)),
|
|
m_format_impl(&handle::format_impl<std::remove_cvref_t<T>>){}
|
|
template<class Context>
|
|
template<class T>
|
|
void basic_format_arg<Context>::handle::format_impl(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx)const{
|
|
using value_type = std::remove_cvref_t<T>;
|
|
using formatter_t = typename Context::template formatter_type<value_type>;
|
|
using qualified_type = std::conditional_t<detail::has_const_formatter<value_type,Context>,
|
|
std::add_const_t<value_type>,
|
|
value_type>;
|
|
using reference_type = std::add_lvalue_reference_t<qualified_type>;
|
|
using pointer_type = std::add_pointer_t<qualified_type>;
|
|
using const_pointer_type = std::add_pointer_t<std::add_const_t<qualified_type>>;
|
|
|
|
reference_type ref = *const_cast<pointer_type>(reinterpret_cast<const_pointer_type>(m_data));
|
|
|
|
formatter_t fmt;
|
|
parse_ctx.advance_to(fmt.parse(parse_ctx));
|
|
format_ctx.advance_to(fmt.format(ref, format_ctx));
|
|
}
|
|
|
|
template<class Context>
|
|
void basic_format_arg<Context>::handle::format(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx)const{
|
|
//Pretty epic gamer moment here
|
|
(this->*m_format_impl)(parse_ctx, format_ctx);
|
|
}
|
|
|
|
///////////////////////////////basic_format_arg////////////////////////////////
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(bool b)noexcept:
|
|
bool_v(b),
|
|
active_member(detail::storage_type::bool_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(char_type b)noexcept:
|
|
char_v(b),
|
|
active_member(detail::storage_type::char_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(int b)noexcept:
|
|
int_v(b),
|
|
active_member(detail::storage_type::int_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(unsigned int b)noexcept:
|
|
uint_v(b),
|
|
active_member(detail::storage_type::uint_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(long long b)noexcept:
|
|
long_long_v(b),
|
|
active_member(detail::storage_type::long_long_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(unsigned long long b)noexcept:
|
|
ulong_long_v(b),
|
|
active_member(detail::storage_type::ulong_long_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(float b)noexcept:
|
|
float_v(b),
|
|
active_member(detail::storage_type::float_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(double b)noexcept:
|
|
double_v(b),
|
|
active_member(detail::storage_type::double_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(long double b)noexcept:
|
|
long_double_v(b),
|
|
active_member(detail::storage_type::long_double_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(const char_type* b)noexcept:
|
|
char_ptr_v(b),
|
|
active_member(detail::storage_type::char_ptr_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(basic_string_view<char_type> b)noexcept:
|
|
string_v(b),
|
|
active_member(detail::storage_type::string_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(const void* b)noexcept:
|
|
ptr_v(b),
|
|
active_member(detail::storage_type::ptr_t){}
|
|
template<class Context>
|
|
basic_format_arg<Context>::basic_format_arg(const handle b)noexcept:
|
|
custom_v(b),
|
|
active_member(detail::storage_type::custom_t){}
|
|
template<class Context>
|
|
detail::storage_type basic_format_arg<Context>::type(void)const{
|
|
return active_member;
|
|
}
|
|
template<class Context>
|
|
basic_format_arg<Context>::operator bool(void)const noexcept{
|
|
return active_member != detail::storage_type::none_t;
|
|
}
|
|
|
|
///////////////////////////////basic_format_args////////////////////////////////
|
|
template<class Context>
|
|
constexpr basic_format_args<Context>::basic_format_args(const detail::basic_format_arg_store<Context>&)noexcept{}
|
|
template<class Context>
|
|
template<class... Args>
|
|
basic_format_args<Context>::basic_format_args(const detail::basic_format_arg_store<Context,Args...>& store)noexcept:
|
|
m_info(store.packed_data.info()),
|
|
m_data(store.packed_data.data()),
|
|
m_num_args(sizeof...(Args)){}
|
|
|
|
template<class Context>
|
|
basic_format_arg<Context> basic_format_args<Context>::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<char_type>) : 0);
|
|
const unsigned char* const data = m_data + offset;
|
|
|
|
switch(m_info[i].type){
|
|
case detail::storage_type::bool_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const bool*>(data)};
|
|
case detail::storage_type::char_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const char_type*>(data)};
|
|
case detail::storage_type::int_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const int*>(data)};
|
|
case detail::storage_type::uint_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const unsigned int*>(data)};
|
|
case detail::storage_type::long_long_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const long long*>(data)};
|
|
case detail::storage_type::ulong_long_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const unsigned long long*>(data)};
|
|
case detail::storage_type::float_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const float*>(data)};
|
|
case detail::storage_type::double_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const double*>(data)};
|
|
case detail::storage_type::long_double_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const long double*>(data)};
|
|
case detail::storage_type::char_ptr_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const char_type* const*>(data)};
|
|
case detail::storage_type::string_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const basic_string_view<char_type>*>(data)};
|
|
case detail::storage_type::ptr_t:
|
|
return basic_format_arg<Context>{reinterpret_cast<const void*>(*reinterpret_cast<const char* const*>(data))};
|
|
case detail::storage_type::custom_t:
|
|
return basic_format_arg<Context>{*reinterpret_cast<const typename basic_format_arg<Context>::handle*>(data)};
|
|
default:
|
|
return basic_format_arg<Context>{};
|
|
};
|
|
}
|
|
template<class Context>
|
|
basic_format_arg<Context> basic_format_args<Context>::get(const char_type* first, const char_type* last)const{
|
|
return get(get_index(first, last));
|
|
}
|
|
template<class Context>
|
|
std::size_t basic_format_args<Context>::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 detail::format_string_view<char_type>* 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<class Fun, class Context>
|
|
decltype(auto) visit_format_arg(Fun&& fun, const basic_format_arg<Context>& arg){
|
|
switch(arg.type()){
|
|
case detail::storage_type::bool_t:
|
|
return std::forward<Fun>(fun)(arg.bool_v);
|
|
case detail::storage_type::char_t:
|
|
return std::forward<Fun>(fun)(arg.char_v);
|
|
case detail::storage_type::int_t:
|
|
return std::forward<Fun>(fun)(arg.int_v);
|
|
case detail::storage_type::uint_t:
|
|
return std::forward<Fun>(fun)(arg.uint_v);
|
|
case detail::storage_type::long_long_t:
|
|
return std::forward<Fun>(fun)(arg.long_long_v);
|
|
case detail::storage_type::ulong_long_t:
|
|
return std::forward<Fun>(fun)(arg.ulong_long_v);
|
|
case detail::storage_type::float_t:
|
|
return std::forward<Fun>(fun)(arg.float_v);
|
|
case detail::storage_type::double_t:
|
|
return std::forward<Fun>(fun)(arg.double_v);
|
|
case detail::storage_type::long_double_t:
|
|
return std::forward<Fun>(fun)(arg.long_double_v);
|
|
case detail::storage_type::char_ptr_t:
|
|
return std::forward<Fun>(fun)(arg.char_ptr_v);
|
|
case detail::storage_type::string_t:
|
|
return std::forward<Fun>(fun)(arg.string_v);
|
|
case detail::storage_type::ptr_t:
|
|
return std::forward<Fun>(fun)(arg.ptr_v);
|
|
case detail::storage_type::custom_t:
|
|
return std::forward<Fun>(fun)(arg.custom_v);
|
|
default:
|
|
REXY_THROW_FORMAT_ERROR("Invalid format_arg storage_type");
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|