157 lines
4.9 KiB
C++
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(1, i, i)}; //don't use 0 index because pointer conversion causes ambiguous call
|
|
{t.size()};
|
|
};
|
|
|
|
template<class It>
|
|
struct something : public It{
|
|
template<class U = something, class C = decltype(U::container)>
|
|
static std::true_type check(int);
|
|
static std::false_type check(...);
|
|
|
|
static constexpr bool value = decltype(check(0))::value;
|
|
};
|
|
|
|
template<class Char, class OutIt>
|
|
OutIt real_write_out(const Char* start, std::size_t write_count, OutIt out){
|
|
static constexpr bool has_container = something<OutIt>::value;//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
|