/**
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_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
#include //size_t
#include //remove_cvref
namespace rexy::fmt::detail{
///////////////////////////////format_handler//////////////////////////////////
template
format_handler::format_handler(out_it_t output, basic_string_view fmt, basic_format_args args):
fmt_ctx(args, output),
parse_ctx(fmt){}
template
format_handler::format_handler(out_it_t output, basic_string_view fmt, basic_format_args args, const std::locale& l):
fmt_ctx(args, output, l),
parse_ctx(fmt){}
template
constexpr auto format_handler::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
constexpr auto format_handler::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, parse_ctx, specs}, arg);
return parse_ctx.begin();
}
template
constexpr auto format_handler::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, parse_ctx}, arg);
return parse_ctx.begin();
}
template
constexpr std::size_t format_handler::on_arg_id(void){
return parse_ctx.next_arg_id();
}
template
constexpr std::size_t format_handler::on_arg_id(std::size_t i){
parse_ctx.check_arg_id(i);
return i;
}
template
constexpr std::size_t format_handler::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
consteval format_checker::format_checker(basic_string_view fmt, std::size_t numargs):
parse_ctx(fmt, numargs){}
template
constexpr auto format_checker::do_raw(fmt_it_t, fmt_it_t last) -> fmt_it_t{
return last;
}
template
constexpr auto format_checker::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
constexpr void format_checker::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
template
constexpr auto format_checker::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;
using base_type = std::remove_cvref_t;
using stored_type = stored_type_t;
if constexpr(Handle){
using fmter_t = typename fmt_ctx_t::template formatter_type;
fmter_t fmter{};
return fmter.parse(parse_ctx);
}else{
dynamic_format_specs specs{};
format_specs_checker> handler{
cx_format_specs_handler{parse_ctx, specs},
detail::map_to_storage_enum_v
};
return parse::perform_standard_parse(start, last, handler);
}
}else{
if constexpr(sizeof...(FArgs) > 0){
return do_format_spec_impl(start, last, id);
}
}
REXY_THROW_FORMAT_ERROR("Missing argument");
}
template
constexpr std::size_t format_checker::on_arg_id(void){
return parse_ctx.next_arg_id();
}
template
constexpr std::size_t format_checker::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
constexpr std::size_t format_checker::on_arg_id(fmt_it_t start, fmt_it_t last){
const std::size_t id = find_static_named_arg_id(start, last);
if(id == invalid_arg_index){
REXY_THROW_FORMAT_ERROR("No such named arg");
}
return on_arg_id(id);
}
}
#endif