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