rexylib/include/rexy/detail/format/output_buffer.tpp

157 lines
4.9 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_OUTPUT_BUFFER_TPP
#define REXY_DETAIL_FORMAT_OUTPUT_BUFFER_TPP
#include "output_buffer.hpp"
#include <cstddef> //size_t
#include <utility> //move
#include <type_traits> //is_pointer, remove_cvref, integral_constant
#include <algorithm> //min
namespace rexy::fmt::detail{
///////////////////////format_output_buffer_base////////////////////////
template<class Char>
void format_output_buffer_base<Char>::clear(void){
m_size = 0;
}
template<class Char>
void format_output_buffer_base<Char>::push_back(Char c){
if(m_size == s_bufsize){
m_written_count += write_out();
clear();
}
m_data[m_size++] = c;
}
template<class Char>
constexpr std::size_t format_output_buffer_base<Char>::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<class Char, class OutIt>
basic_format_output_buffer<Char,OutIt>::basic_format_output_buffer(OutIt out):
m_out(out){}
template<class Char, class OutIt>
basic_format_output_buffer<Char,OutIt>::~basic_format_output_buffer(void){
write_out();
}
template<class T>
concept HasContainerAlias = requires{
typename T::container_type;
};
template<class T, class It>
concept HasInsertMethod = requires(T t, It i){
{t.insert(0, i, i)};
{t.size()};
};
struct container_traits_helper{
using container = int;
};
template<class It>
struct container_traits : public It, public container_traits_helper{
template<class T = container_traits, class U = typename T::container>
static std::false_type check(int);
static std::true_type check(...);
};
template<class Char, class OutIt>
OutIt real_write_out(const Char* start, std::size_t write_count, OutIt out){
static constexpr bool has_container = decltype(container_traits<OutIt>::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<OutIt>){
struct container_access : public OutIt{
using OutIt::container;
};
container_access ca{out};
auto& container = ca.container;
if constexpr(HasInsertMethod<typename OutIt::container_type,const Char*>){
if constexpr(std::is_pointer_v<std::remove_cvref_t<decltype(container)>>){
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<class Char, class OutIt>
std::size_t basic_format_output_buffer<Char,OutIt>::write_out(void){
m_out = real_write_out(this->m_data, this->m_size, std::move(m_out));
return this->m_size;
}
template<class Char, class OutIt>
constexpr OutIt basic_format_output_buffer<Char,OutIt>::out(void){
return std::move(m_out);
}
///////////////////////basic_format_output_n_buffer////////////////////////
template<class Char, class OutIt>
basic_format_output_n_buffer<Char,OutIt>::basic_format_output_n_buffer(OutIt out, std::size_t max):
m_out(out),
m_max_write(max){}
template<class Char, class OutIt>
basic_format_output_n_buffer<Char,OutIt>::~basic_format_output_n_buffer(void){
write_out();
}
template<class Char, class OutIt>
std::size_t basic_format_output_n_buffer<Char,OutIt>::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<class Char, class OutIt>
constexpr OutIt basic_format_output_n_buffer<Char,OutIt>::out(void){
return std::move(m_out);
}
/////////////////////////basic_format_size_buffer//////////////////////////
template<class Char>
constexpr basic_format_size_buffer<Char>::~basic_format_size_buffer(void){
write_out();
}
template<class Char>
std::size_t basic_format_size_buffer<Char>::write_out(void){
return this->m_size;
}
}
#endif