format.hpp
//
// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
//
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_LOCALE_FORMAT_HPP_INCLUDED
#define BOOST_LOCALE_FORMAT_HPP_INCLUDED
#include <boost/locale/config.hpp>
#include <boost/locale/formatting.hpp>
#include <boost/locale/hold_ptr.hpp>
#include <boost/locale/message.hpp>
#include <sstream>
#include <stdexcept>
#include <vector>
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable : 4275 4251 4231 4660)
#endif
namespace boost { namespace locale {
namespace detail {
template<typename CharType>
struct formattible {
typedef std::basic_ostream<CharType> stream_type;
typedef void (*writer_type)(stream_type& output, const void* ptr);
formattible() : pointer_(0), writer_(&formattible::void_write) {}
formattible(const formattible& other) = default;
formattible(formattible&& other) = default;
formattible& operator=(const formattible& other) = default;
formattible& operator=(formattible&& other) = default;
template<typename Type>
explicit formattible(const Type& value)
{
pointer_ = static_cast<const void*>(&value);
writer_ = &write<Type>;
}
friend stream_type& operator<<(stream_type& out, const formattible& fmt)
{
fmt.writer_(out, fmt.pointer_);
return out;
}
private:
static void void_write(stream_type& output, const void* /*ptr*/)
{
CharType empty_string[1] = {0};
output << empty_string;
}
template<typename Type>
static void write(stream_type& output, const void* ptr)
{
output << *static_cast<const Type*>(ptr);
}
const void* pointer_;
writer_type writer_;
}; // formattible
class BOOST_LOCALE_DECL format_parser {
public:
format_parser(std::ios_base& ios, void*, void (*imbuer)(void*, const std::locale&));
~format_parser();
format_parser(const format_parser&) = delete;
format_parser& operator=(const format_parser&) = delete;
unsigned get_position();
void set_one_flag(const std::string& key, const std::string& value);
template<typename CharType>
void set_flag_with_str(const std::string& key, const std::basic_string<CharType>& value)
{
if(key == "ftime" || key == "strftime") {
as::strftime(ios_);
ios_info::get(ios_).date_time_pattern(value);
}
}
void restore();
private:
void imbue(const std::locale&);
std::ios_base& ios_;
struct data;
hold_ptr<data> d;
};
} // namespace detail
template<typename CharType>
class basic_format {
public:
typedef CharType char_type;
typedef basic_message<char_type> message_type;
typedef detail::formattible<CharType> formattible_type;
typedef std::basic_string<CharType> string_type;
typedef std::basic_ostream<CharType> stream_type;
basic_format(const string_type& format_string) : format_(format_string), translate_(false), parameters_count_(0)
{}
basic_format(const message_type& trans) : message_(trans), translate_(true), parameters_count_(0) {}
basic_format(const basic_format& other) = delete;
void operator=(const basic_format& other) = delete;
basic_format(basic_format&& other) :
message_(std::move(other.message_)), format_(std::move(other.format_)), translate_(other.translate_),
parameters_count_(0)
{
if(other.parameters_count_)
throw std::invalid_argument("Can't move a basic_format with bound parameters");
}
basic_format& operator=(basic_format&& other)
{
if(other.parameters_count_)
throw std::invalid_argument("Can't move a basic_format with bound parameters");
message_ = std::move(other.message_);
format_ = std::move(other.format_);
translate_ = other.translate_;
parameters_count_ = 0;
ext_params_.clear();
return *this;
}
template<typename Formattible>
basic_format& operator%(const Formattible& object)
{
add(formattible_type(object));
return *this;
}
string_type str(const std::locale& loc = std::locale()) const
{
std::basic_ostringstream<CharType> buffer;
buffer.imbue(loc);
write(buffer);
return buffer.str();
}
void write(stream_type& out) const
{
string_type format;
if(translate_)
format = message_.str(out.getloc(), ios_info::get(out).domain_id());
else
format = format_;
format_output(out, format);
}
private:
class format_guard {
public:
format_guard(detail::format_parser& fmt) : fmt_(&fmt), restored_(false) {}
void restore()
{
if(restored_)
return;
fmt_->restore();
restored_ = true;
}
~format_guard()
{
try {
restore();
} catch(...) {
}
}
private:
detail::format_parser* fmt_;
bool restored_;
};
void format_output(stream_type& out, const string_type& sformat) const
{
char_type obrk = '{';
char_type cbrk = '}';
char_type eq = '=';
char_type comma = ',';
char_type quote = '\'';
size_t pos = 0;
size_t size = sformat.size();
const CharType* format = sformat.c_str();
while(format[pos] != 0) {
if(format[pos] != obrk) {
if(format[pos] == cbrk && format[pos + 1] == cbrk) {
out << cbrk;
pos += 2;
} else {
out << format[pos];
pos++;
}
continue;
}
if(pos + 1 < size && format[pos + 1] == obrk) {
out << obrk;
pos += 2;
continue;
}
pos++;
detail::format_parser fmt(out, static_cast<void*>(&out), &basic_format::imbue_locale);
format_guard guard(fmt);
while(pos < size) {
std::string key;
std::string svalue;
string_type value;
bool use_svalue = true;
for(; format[pos]; pos++) {
char_type c = format[pos];
if(c == comma || c == eq || c == cbrk)
break;
else {
key += static_cast<char>(c);
}
}
if(format[pos] == eq) {
pos++;
if(format[pos] == quote) {
pos++;
use_svalue = false;
while(format[pos]) {
if(format[pos] == quote) {
if(format[pos + 1] == quote) {
value += quote;
pos += 2;
} else {
pos++;
break;
}
} else {
value += format[pos];
pos++;
}
}
} else {
char_type c;
while((c = format[pos]) != 0 && c != comma && c != cbrk) {
svalue += static_cast<char>(c);
pos++;
}
}
}
if(use_svalue) {
fmt.set_one_flag(key, svalue);
} else
fmt.set_flag_with_str(key, value);
if(format[pos] == comma) {
pos++;
continue;
} else if(format[pos] == cbrk) {
unsigned position = fmt.get_position();
out << get(position);
guard.restore();
pos++;
break;
} else {
guard.restore();
break;
}
}
}
}
void add(const formattible_type& param)
{
if(parameters_count_ >= base_params_)
ext_params_.push_back(param);
else
parameters_[parameters_count_] = param;
parameters_count_++;
}
formattible_type get(unsigned id) const
{
if(id >= parameters_count_)
return formattible_type();
else if(id >= base_params_)
return ext_params_[id - base_params_];
else
return parameters_[id];
}
static void imbue_locale(void* ptr, const std::locale& l) { reinterpret_cast<stream_type*>(ptr)->imbue(l); }
static constexpr unsigned base_params_ = 8;
message_type message_;
string_type format_;
bool translate_;
formattible_type parameters_[base_params_];
unsigned parameters_count_;
std::vector<formattible_type> ext_params_;
};
template<typename CharType>
std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& out, const basic_format<CharType>& fmt)
{
fmt.write(out);
return out;
}
typedef basic_format<char> format;
typedef basic_format<wchar_t> wformat;
#ifdef BOOST_LOCALE_ENABLE_CHAR16_T
typedef basic_format<char16_t> u16format;
#endif
#ifdef BOOST_LOCALE_ENABLE_CHAR32_T
typedef basic_format<char32_t> u32format;
#endif
}} // namespace boost::locale
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
#endif
boost::locale::u32format
basic_format< char32_t > u32format
Definition of char32_t based format.
Definition: format.hpp:439
boost::locale::basic_format
a printf like class that allows type-safe and locale aware message formatting
Definition: format.hpp:180
boost::locale::basic_format::basic_format
basic_format(const message_type &trans)
Definition: format.hpp:196
boost::locale::basic_format::string_type
std::basic_string< CharType > string_type
string type for this type of character
Definition: format.hpp:188
boost::locale::as::strftime
std::ios_base & strftime(std::ios_base &ios)
Definition: formatting.hpp:254
boost::locale::basic_format::operator%
basic_format & operator%(const Formattible &object)
Definition: format.hpp:236
boost::locale::basic_message< char_type >
boost::locale::basic_message::str
string_type str() const
Translate message to a string in the default global locale, using default domain.
Definition: message.hpp:229
boost::locale::basic_format::str
string_type str(const std::locale &loc=std::locale()) const
Format a string using a locale loc.
Definition: format.hpp:243
boost::locale::ios_info::get
static ios_info & get(std::ios_base &ios)
Get ios_info instance for specific stream object.
boost::locale::basic_format::basic_format
basic_format(const string_type &format_string)
Create a format class for format_string.
Definition: format.hpp:192
boost::locale::basic_format::basic_format
basic_format(basic_format &&other)
Moveable.
Definition: format.hpp:202
boost::locale::basic_format::stream_type
std::basic_ostream< CharType > stream_type
output stream type for this type of character
Definition: format.hpp:189
boost::locale::operator<<
std::basic_ostream< CharType > & operator<<(std::basic_ostream< CharType > &out, const date_time &t)
Definition: date_time.hpp:719
boost::locale::ios_info::domain_id
void domain_id(int)
Set special message domain identification.
boost::locale::ios_info::date_time_pattern
void date_time_pattern(const std::basic_string< CharType > &str)
Set date/time pattern (strftime like)
Definition: formatting.hpp:131
boost::locale::basic_format::write
void write(stream_type &out) const
write a formatted string to output stream out using out's locale
Definition: format.hpp:252
boost::locale::basic_format::char_type
CharType char_type
Underlying character type.
Definition: format.hpp:182
boost::locale::wformat
basic_format< wchar_t > wformat
Definition of wchar_t based format.
Definition: format.hpp:430
boost::locale::u16format
basic_format< char16_t > u16format
Definition of char16_t based format.
Definition: format.hpp:434
boost::locale::format
basic_format< char > format
Definition of char based format.
Definition: format.hpp:428
boost::locale::basic_format::message_type
basic_message< char_type > message_type
Definition: format.hpp:183
- © Copyright 2009-2012 Artyom Beilis, Distributed under the Boost Software License, Version 1.0.