163 lines
5.6 KiB
C++
163 lines
5.6 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_CONTEXT_HANDLER_TPP
|
|
#define REXY_DETAIL_FORMAT_CONTEXT_HANDLER_TPP
|
|
|
|
#include "context_handler.hpp"
|
|
|
|
#include "parse_context.hpp"
|
|
#include "format_context.hpp"
|
|
#include "formatter.hpp"
|
|
#include "format_args.hpp"
|
|
#include "named_args.hpp"
|
|
|
|
#include "format_error.hpp"
|
|
|
|
#include "../../string_view.hpp"
|
|
|
|
#include <locale> //locale
|
|
#include <cstddef> //size_t
|
|
#include <type_traits> //remove_cvref
|
|
|
|
namespace rexy::fmt::detail{
|
|
|
|
///////////////////////////////format_handler//////////////////////////////////
|
|
template<class Char>
|
|
format_handler<Char>::format_handler(out_it_t output, basic_string_view<char_type> fmt, basic_format_args<fmt_ctx_t> args):
|
|
fmt_ctx(args, output),
|
|
parse_ctx(fmt){}
|
|
template<class Char>
|
|
format_handler<Char>::format_handler(out_it_t output, basic_string_view<char_type> fmt, basic_format_args<fmt_ctx_t> args, const std::locale& l):
|
|
fmt_ctx(args, output, l),
|
|
parse_ctx(fmt){}
|
|
|
|
template<class Char>
|
|
constexpr auto format_handler<Char>::do_raw(fmt_it_t start, fmt_it_t fin) -> fmt_it_t{
|
|
for(auto it = start;it != fin;++it){
|
|
fmt_ctx.out() = *it;
|
|
}
|
|
return fin;
|
|
}
|
|
template<class Char>
|
|
constexpr auto format_handler<Char>::do_format_spec(fmt_it_t start, fmt_it_t fin, std::size_t id) -> fmt_it_t{
|
|
parse_ctx.advance_to(start);
|
|
const auto arg = fmt_ctx.arg(id);
|
|
format_specs specs;
|
|
visit_format_arg(format::arg_formatter<fmt_ctx_t,parse_ctx_t,format_specs>{fmt_ctx, parse_ctx, specs}, arg);
|
|
return parse_ctx.begin();
|
|
}
|
|
|
|
template<class Char>
|
|
constexpr auto format_handler<Char>::do_empty_format(fmt_it_t start, fmt_it_t last, std::size_t id) -> fmt_it_t{
|
|
parse_ctx.advance_to(start);
|
|
const auto arg = fmt_ctx.arg(id);
|
|
visit_format_arg(format::empty_formatter<fmt_ctx_t,parse_ctx_t>{fmt_ctx, parse_ctx}, arg);
|
|
return parse_ctx.begin();
|
|
}
|
|
|
|
template<class Char>
|
|
constexpr std::size_t format_handler<Char>::on_arg_id(void){
|
|
return parse_ctx.next_arg_id();
|
|
}
|
|
template<class Char>
|
|
constexpr std::size_t format_handler<Char>::on_arg_id(std::size_t i){
|
|
parse_ctx.check_arg_id(i);
|
|
return i;
|
|
}
|
|
template<class Char>
|
|
constexpr std::size_t format_handler<Char>::on_arg_id(fmt_it_t start, fmt_it_t last){
|
|
const auto id = fmt_ctx.arg_index(start, last);
|
|
parse_ctx.check_arg_id(id);
|
|
return id;
|
|
}
|
|
|
|
|
|
///////////////////////////////format_checker//////////////////////////////////
|
|
template<class Char, class... Args>
|
|
consteval format_checker<Char,Args...>::format_checker(basic_string_view<char_type> fmt, std::size_t numargs):
|
|
parse_ctx(fmt, numargs){}
|
|
template<class Char, class... Args>
|
|
constexpr auto format_checker<Char,Args...>::do_raw(fmt_it_t, fmt_it_t last) -> fmt_it_t{
|
|
return last;
|
|
}
|
|
template<class Char, class... Args>
|
|
constexpr auto format_checker<Char,Args...>::do_format_spec(fmt_it_t start, fmt_it_t last, std::size_t id) -> fmt_it_t{
|
|
parse_ctx.advance_to(start);
|
|
if constexpr(sizeof...(Args)){
|
|
return do_format_spec_impl<0,Args...>(start, last, id);
|
|
}else{
|
|
REXY_THROW_FORMAT_ERROR("Missing argument");
|
|
return start;
|
|
}
|
|
}
|
|
template<class Char, class... Args>
|
|
constexpr void format_checker<Char,Args...>::do_empty_format(fmt_it_t, fmt_it_t, std::size_t){/*nothing to parse and the checker doesn't format so just return*/}
|
|
template<class Char, class... Args>
|
|
template<std::size_t I, class FArg, class... FArgs>
|
|
constexpr auto format_checker<Char,Args...>::do_format_spec_impl(fmt_it_t start, fmt_it_t last, std::size_t id) -> fmt_it_t{
|
|
if(I == id){
|
|
using fmt_ctx_t = fmt_context_t<Char>;
|
|
using base_type = std::remove_cvref_t<FArg>;
|
|
using stored_type = stored_type_t<base_type,fmt_ctx_t>;
|
|
if constexpr(Handle<stored_type,fmt_ctx_t>){
|
|
using fmter_t = typename fmt_ctx_t::template formatter_type<base_type>;
|
|
fmter_t fmter{};
|
|
return fmter.parse(parse_ctx);
|
|
}else{
|
|
dynamic_format_specs<Char> specs{};
|
|
format_specs_checker<cx_format_specs_handler<parse_ctx_t,Args...>> handler{
|
|
cx_format_specs_handler<parse_ctx_t,Args...>{parse_ctx, specs},
|
|
detail::map_to_storage_enum_v<stored_type,Char>
|
|
};
|
|
return parse::perform_standard_parse(start, last, handler);
|
|
}
|
|
}else{
|
|
if constexpr(sizeof...(FArgs) > 0){
|
|
return do_format_spec_impl<I+1,FArgs...>(start, last, id);
|
|
}
|
|
}
|
|
REXY_THROW_FORMAT_ERROR("Missing argument");
|
|
}
|
|
|
|
template<class Char, class... Args>
|
|
constexpr std::size_t format_checker<Char,Args...>::on_arg_id(void){
|
|
return parse_ctx.next_arg_id();
|
|
}
|
|
template<class Char, class... Args>
|
|
constexpr std::size_t format_checker<Char,Args...>::on_arg_id(std::size_t i){
|
|
if(i > sizeof...(Args)){
|
|
REXY_THROW_FORMAT_ERROR("Arg index out of bounds");
|
|
}
|
|
parse_ctx.check_arg_id(i);
|
|
return i;
|
|
}
|
|
template<class Char, class... Args>
|
|
constexpr std::size_t format_checker<Char,Args...>::on_arg_id(fmt_it_t start, fmt_it_t last){
|
|
const std::size_t id = find_static_named_arg_id<fmt_it_t, Args...>(start, last);
|
|
if(id == invalid_arg_index){
|
|
REXY_THROW_FORMAT_ERROR("No such named arg");
|
|
}
|
|
return on_arg_id(id);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
#endif
|