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