/** 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_OUTPUT_BUFFER_TPP #define REXY_DETAIL_FORMAT_OUTPUT_BUFFER_TPP #include "output_buffer.hpp" #include //size_t #include //move #include //is_pointer, remove_cvref, integral_constant #include //min namespace rexy::fmt::detail{ ///////////////////////format_output_buffer_base//////////////////////// template void format_output_buffer_base::clear(void){ m_size = 0; } template void format_output_buffer_base::push_back(Char c){ if(m_size == s_bufsize){ m_written_count += write_out(); clear(); } m_data[m_size++] = c; } template constexpr std::size_t format_output_buffer_base::count(void)const{ //include data that will be written during next call to write_out return m_written_count + m_size; } ///////////////////////basic_format_output_buffer//////////////////////// template basic_format_output_buffer::basic_format_output_buffer(OutIt out): m_out(out){} template basic_format_output_buffer::~basic_format_output_buffer(void){ write_out(); } template concept HasContainerAlias = requires{ typename T::container_type; }; template concept HasInsertMethod = requires(T t, It i){ {t.insert(1, i, i)}; //don't use 0 index because pointer conversion causes ambiguous call {t.size()}; }; template struct something : public It{ template static std::true_type check(int); static std::false_type check(...); static constexpr bool value = decltype(check(0))::value; }; template OutIt real_write_out(const Char* start, std::size_t write_count, OutIt out){ static constexpr bool has_container = something::value;//decltype(container_traits::check(0))::value; //optimize for types where direct access to the underlying container is available //check for a container member and a 'container_type' typedef in OutIt //reason for the type check is that without 'container_type' it might not be safe to access the 'container' if constexpr(has_container && HasContainerAlias){ struct container_access : public OutIt{ using OutIt::container; }; container_access ca{out}; auto& container = ca.container; if constexpr(HasInsertMethod){ if constexpr(std::is_pointer_v>){ container->insert(container->size(), start, start + write_count); }else{ container.insert(container.size(), start, start + write_count); } return std::move(out); } } for(std::size_t i = 0;i < write_count;++i){ out = start[i]; } return std::move(out); } template std::size_t basic_format_output_buffer::write_out(void){ m_out = real_write_out(this->m_data, this->m_size, std::move(m_out)); return this->m_size; } template constexpr OutIt basic_format_output_buffer::out(void){ return std::move(m_out); } ///////////////////////basic_format_output_n_buffer//////////////////////// template basic_format_output_n_buffer::basic_format_output_n_buffer(OutIt out, std::size_t max): m_out(out), m_max_write(max){} template basic_format_output_n_buffer::~basic_format_output_n_buffer(void){ write_out(); } template std::size_t basic_format_output_n_buffer::write_out(void){ const auto to_write = std::min(this->size, m_max_write); m_out = real_write_out(this->m_data, to_write, std::move(m_out)); m_max_write -= to_write; return to_write; } template constexpr OutIt basic_format_output_n_buffer::out(void){ return std::move(m_out); } /////////////////////////basic_format_size_buffer////////////////////////// template constexpr basic_format_size_buffer::~basic_format_size_buffer(void){ write_out(); } template std::size_t basic_format_size_buffer::write_out(void){ return this->m_size; } } #endif