Commit c0954453 authored by Victor Zverovich's avatar Victor Zverovich

Replace buffer with range

parent c3d6c5fc
/*
Formatting library for C++
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - the core API
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_CORE_H_
#define FMT_CORE_H_
#include <cassert>
#include <cstdio>
#include <cstring>
#include <string>
#include <type_traits>
......@@ -92,36 +73,15 @@
# define FMT_ASSERT(condition, message) assert((condition) && message)
#endif
#define FMT_DELETED = delete
// A macro to disallow the copy construction and assignment.
#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
TypeName& operator=(const TypeName&) = delete
#define FMT_DELETED_OR_UNDEFINED = delete
#define FMT_DISALLOW_COPY_AND_ASSIGN(Type) \
Type(const Type &) FMT_DELETED; \
void operator=(const Type &) FMT_DELETED
namespace fmt {
template <typename T>
class basic_buffer;
using buffer = basic_buffer<char>;
using wbuffer = basic_buffer<wchar_t>;
template <typename Context>
class basic_arg;
template <typename Context>
class basic_format_args;
template <typename Char>
class basic_context;
using context = basic_context<char>;
using wcontext = basic_context<wchar_t>;
// A formatter for objects of type T.
template <typename T, typename Char = char, typename Enable = void>
struct formatter;
/**
\rst
An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
......@@ -138,10 +98,10 @@ class basic_string_view {
using char_type = Char;
using iterator = const Char *;
constexpr basic_string_view() noexcept : data_(0), size_(0) {}
constexpr basic_string_view() FMT_NOEXCEPT : data_(0), size_(0) {}
/** Constructs a string reference object from a C string and a size. */
constexpr basic_string_view(const Char *s, size_t size) noexcept
constexpr basic_string_view(const Char *s, size_t size) FMT_NOEXCEPT
: data_(s), size_(size) {}
/**
......@@ -158,7 +118,7 @@ class basic_string_view {
Constructs a string reference from an ``std::string`` object.
\endrst
*/
constexpr basic_string_view(const std::basic_string<Char> &s) noexcept
constexpr basic_string_view(const std::basic_string<Char> &s) FMT_NOEXCEPT
: data_(s.c_str()), size_(s.size()) {}
/**
......@@ -216,6 +176,96 @@ class basic_string_view {
using string_view = basic_string_view<char>;
using wstring_view = basic_string_view<wchar_t>;
/** A contiguous memory buffer with an optional growing ability. */
template <typename T>
class basic_buffer {
private:
FMT_DISALLOW_COPY_AND_ASSIGN(basic_buffer);
T *ptr_;
std::size_t size_;
std::size_t capacity_;
protected:
basic_buffer() FMT_NOEXCEPT : ptr_(0), size_(0), capacity_(0) {}
/** Sets the buffer data and capacity. */
void set(T *data, std::size_t capacity) FMT_NOEXCEPT {
ptr_ = data;
capacity_ = capacity;
}
/**
\rst
Increases the buffer capacity to hold at least *capacity* elements.
\endrst
*/
virtual void grow(std::size_t capacity) = 0;
public:
using value_type = T;
virtual ~basic_buffer() {}
T *begin() FMT_NOEXCEPT { return ptr_; }
T *end() FMT_NOEXCEPT { return ptr_ + size_; }
/** Returns the size of this buffer. */
std::size_t size() const FMT_NOEXCEPT { return size_; }
/** Returns the capacity of this buffer. */
std::size_t capacity() const FMT_NOEXCEPT { return capacity_; }
/** Returns a pointer to the buffer data. */
T *data() FMT_NOEXCEPT { return ptr_; }
/** Returns a pointer to the buffer data. */
const T *data() const FMT_NOEXCEPT { return ptr_; }
/**
Resizes the buffer. If T is a POD type new elements may not be initialized.
*/
void resize(std::size_t new_size) {
reserve(new_size);
size_ = new_size;
}
/**
\rst
Reserves space to store at least *capacity* elements.
\endrst
*/
void reserve(std::size_t capacity) {
if (capacity > capacity_)
grow(capacity);
}
void push_back(const T &value) {
reserve(size_ + 1);
ptr_[size_++] = value;
}
/** Appends data to the end of the buffer. */
template <typename U>
void append(const U *begin, const U *end);
T &operator[](std::size_t index) { return ptr_[index]; }
const T &operator[](std::size_t index) const { return ptr_[index]; }
};
using buffer = basic_buffer<char>;
using wbuffer = basic_buffer<wchar_t>;
template <typename Context>
class basic_arg;
template <typename Context>
class basic_format_args;
// A formatter for objects of type T.
template <typename T, typename Char = char, typename Enable = void>
struct formatter;
namespace internal {
template <typename T>
......@@ -286,14 +336,17 @@ FMT_DISABLE_CONVERSION_TO_INT(float);
FMT_DISABLE_CONVERSION_TO_INT(double);
FMT_DISABLE_CONVERSION_TO_INT(long double);
template <typename Context>
template <typename Char>
struct named_arg_base;
template <typename T, typename Char>
struct named_arg;
template <typename T>
struct is_named_arg : std::false_type {};
template <typename Context>
struct is_named_arg<named_arg<Context>> : std::true_type {};
template <typename T, typename Char>
struct is_named_arg<named_arg<T, Char>> : std::true_type {};
enum type {
NONE, NAMED_ARG,
......@@ -370,6 +423,9 @@ constexpr uint64_t get_types() {
template <>
constexpr uint64_t get_types<void>() { return 0; }
template <typename Context, typename T>
constexpr basic_arg<Context> make_arg(const T &value);
template <typename Char>
struct string_value {
const Char *value;
......@@ -378,12 +434,8 @@ struct string_value {
template <typename Context>
struct custom_value {
using format_func = void (*)(
basic_buffer<typename Context::char_type> &buffer,
const void *arg, Context &ctx);
const void *value;
format_func format;
void (*format)(const void *arg, Context &ctx);
};
// A formatting argument value.
......@@ -487,13 +539,17 @@ class value {
custom.format = &format_custom_arg<T>;
}
// Additional template param `Ctx` is needed here because get_type always
// uses basic_context<char>.
template <typename Ctx>
value(const named_arg<Ctx> &value) {
static_assert(
get_type<const named_arg<Ctx> &>() == NAMED_ARG, "invalid type");
pointer = &value;
template <typename T>
value(const named_arg<T, char_type> &na) {
static_assert(get_type<const named_arg<T, char_type> &>() == NAMED_ARG,
"invalid type");
basic_arg<Context> arg = make_arg<Context>(na.value);
std::memcpy(na.data, &arg, sizeof(arg));
pointer = &na;
}
const named_arg_base<char_type> &as_named_arg() {
return *static_cast<const named_arg_base<char_type>*>(pointer);
}
private:
......@@ -519,15 +575,14 @@ class value {
// Formats an argument of a custom type, such as a user-defined class.
template <typename T>
static void format_custom_arg(
basic_buffer<char_type> &buffer, const void *arg, Context &ctx) {
static void format_custom_arg(const void *arg, Context &ctx) {
// Get the formatter type through the context to allow different contexts
// have different extension points, e.g. `formatter<T>` for `format` and
// `printf_formatter<T>` for `printf`.
typename Context::template formatter_type<T> f;
auto &&parse_ctx = ctx.parse_context();
parse_ctx.advance_to(f.parse(parse_ctx));
f.format(buffer, *static_cast<const T*>(arg), ctx);
f.format(*static_cast<const T*>(arg), ctx);
}
};
......@@ -536,9 +591,6 @@ enum { MAX_PACKED_ARGS = 15 };
template <typename Context>
class arg_map;
template <typename Context, typename T>
constexpr basic_arg<Context> make_arg(const T &value);
}
// A formatting argument. It is a trivially copyable/constructible type to
......@@ -574,7 +626,9 @@ class basic_arg {
constexpr basic_arg() : type_(internal::NONE) {}
explicit operator bool() const noexcept { return type_ != internal::NONE; }
explicit operator bool() const FMT_NOEXCEPT {
return type_ != internal::NONE;
}
internal::type type() const { return type_; }
......@@ -648,27 +702,16 @@ constexpr basic_arg<Context> make_arg(const T &value) {
template <bool IS_PACKED, typename Context, typename T>
inline typename std::enable_if<IS_PACKED, value<Context>>::type
make_arg(const T& value) {
make_arg(const T &value) {
return value;
}
template <bool IS_PACKED, typename Context, typename T>
inline typename std::enable_if<!IS_PACKED, basic_arg<Context>>::type
make_arg(const T& value) {
make_arg(const T &value) {
return make_arg<Context>(value);
}
template <typename Context>
struct named_arg : basic_arg<Context> {
using char_type = typename Context::char_type;
basic_string_view<char_type> name;
template <typename T>
named_arg(basic_string_view<char_type> argname, const T &value)
: basic_arg<Context>(make_arg<Context>(value)), name(argname) {}
};
template <typename Context>
class arg_map {
private:
......@@ -676,16 +719,17 @@ class arg_map {
using char_type = typename Context::char_type;
struct arg {
struct entry {
basic_string_view<char_type> name;
basic_arg<Context> value;
basic_arg<Context> arg;
};
arg *map_ = nullptr;
entry *map_ = nullptr;
unsigned size_ = 0;
void push_back(arg a) {
map_[size_] = a;
void push_back(value<Context> val) {
const internal::named_arg_base<char_type> &named = val.as_named_arg();
map_[size_] = entry{named.name, named.template deserialize<Context>()};
++size_;
}
......@@ -694,29 +738,29 @@ class arg_map {
void init(const basic_format_args<Context> &args);
~arg_map() { delete [] map_; }
const basic_arg<Context>
*find(const basic_string_view<char_type> &name) const {
basic_arg<Context> find(basic_string_view<char_type> name) const {
// The list is unsorted, so just return the first matching name.
for (auto it = map_, end = map_ + size_; it != end; ++it) {
if (it->name == name)
return &it->value;
return it->arg;
}
return 0;
return basic_arg<Context>();
}
};
template <typename Char, typename Context>
class context_base : public basic_parse_context<Char>{
template <typename Range, typename Context>
class context_base : public basic_parse_context<typename Range::value_type> {
private:
Range &range_;
basic_format_args<Context> args_;
protected:
using char_type = typename Range::value_type;
using format_arg = basic_arg<Context>;
context_base(basic_string_view<Char> format_str,
context_base(Range &range, basic_string_view<char_type> format_str,
basic_format_args<Context> args)
: basic_parse_context<Char>(format_str), args_(args) {}
~context_base() {}
: basic_parse_context<char_type>(format_str), range_(range), args_(args) {}
basic_format_args<Context> args() const { return args_; }
......@@ -736,29 +780,30 @@ class context_base : public basic_parse_context<Char>{
}
public:
basic_parse_context<Char> &parse_context() { return *this; }
basic_parse_context<char_type> &parse_context() { return *this; }
Range &range() { return range_; }
};
} // namespace internal
template <typename Char>
template <typename Range>
class basic_context :
public internal::context_base<Char, basic_context<Char>> {
public internal::context_base<Range, basic_context<Range>> {
public:
/** The character type for the output. */
using char_type = Char;
using char_type = typename Range::value_type;
template <typename T>
using formatter_type = formatter<T, Char>;
using formatter_type = formatter<T, char_type>;
private:
internal::arg_map<basic_context<Char>> map_;
internal::arg_map<basic_context> map_;
FMT_DISALLOW_COPY_AND_ASSIGN(basic_context);
using Base = internal::context_base<Char, basic_context<Char>>;
using base = internal::context_base<Range, basic_context>;
using format_arg = typename Base::format_arg;
using Base::get_arg;
using format_arg = typename base::format_arg;
using base::get_arg;
public:
/**
......@@ -767,18 +812,21 @@ class basic_context :
stored in the object so make sure they have appropriate lifetimes.
\endrst
*/
basic_context(
basic_string_view<Char> format_str, basic_format_args<basic_context> args)
: Base(format_str, args) {}
basic_context(Range &range, basic_string_view<char_type> format_str,
basic_format_args<basic_context> args)
: base(range, format_str, args) {}
format_arg next_arg() { return this->do_get_arg(this->next_arg_id()); }
format_arg get_arg(unsigned arg_id) { return this->do_get_arg(arg_id); }
// Checks if manual indexing is used and returns the argument with
// specified name.
format_arg get_arg(basic_string_view<Char> name);
format_arg get_arg(basic_string_view<char_type> name);
};
using context = basic_context<buffer>;
using wcontext = basic_context<wbuffer>;
template <typename Context, typename ...Args>
class arg_store {
private:
......@@ -876,7 +924,7 @@ class basic_format_args {
format_arg operator[](size_type index) const {
format_arg arg = get(index);
return arg.type_ == internal::NAMED_ARG ?
*static_cast<const format_arg*>(arg.value_.pointer) : arg;
arg.value_.as_named_arg().template deserialize<Context>() : arg;
}
unsigned max_size() const {
......@@ -888,6 +936,31 @@ class basic_format_args {
using format_args = basic_format_args<context>;
using wformat_args = basic_format_args<wcontext>;
namespace internal {
template <typename Char>
struct named_arg_base {
basic_string_view<Char> name;
// Serialized value<context>.
mutable char data[sizeof(basic_arg<context>)];
template <typename Context>
basic_arg<Context> deserialize() const {
basic_arg<Context> arg;
std::memcpy(&arg, data, sizeof(basic_arg<Context>));
return arg;
}
};
template <typename T, typename Char>
struct named_arg : named_arg_base<Char> {
const T &value;
named_arg(basic_string_view<Char> name, const T &val)
: named_arg_base<Char>{name}, value(val) {}
};
}
/**
\rst
Returns a named argument for formatting functions.
......@@ -895,25 +968,24 @@ using wformat_args = basic_format_args<wcontext>;
**Example**::
print("Elapsed time: {s:.2f} seconds", arg("s", 1.23));
\endrst
*/
template <typename T>
inline internal::named_arg<context> arg(string_view name, const T &arg) {
return internal::named_arg<context>(name, arg);
inline internal::named_arg<T, char> arg(string_view name, const T &arg) {
return internal::named_arg<T, char>(name, arg);
}
template <typename T>
inline internal::named_arg<wcontext> arg(wstring_view name, const T &arg) {
return internal::named_arg<wcontext>(name, arg);
inline internal::named_arg<T, wchar_t> arg(wstring_view name, const T &arg) {
return internal::named_arg<T, wchar_t>(name, arg);
}
// The following two functions are deleted intentionally to disable
// nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``.
template <typename Context>
void arg(string_view, internal::named_arg<Context>) FMT_DELETED_OR_UNDEFINED;
template <typename Context>
void arg(wstring_view, internal::named_arg<Context>) FMT_DELETED_OR_UNDEFINED;
template <typename T>
void arg(string_view, internal::named_arg<T, char>) FMT_DELETED;
template <typename T>
void arg(wstring_view, internal::named_arg<T, wchar_t>) FMT_DELETED;
enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE };
......
/*
Formatting library for C++
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/format.h"
#include "fmt/locale.h"
......@@ -348,18 +328,18 @@ FMT_FUNC void windows_error::init(
FMT_FUNC void internal::format_windows_error(
buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
FMT_TRY {
wmemory_buffer buffer;
buffer.resize(INLINE_BUFFER_SIZE);
wmemory_buffer buf;
buf.resize(INLINE_BUFFER_SIZE);
for (;;) {
wchar_t *system_message = &buffer[0];
wchar_t *system_message = &buf[0];
int result = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
system_message, static_cast<uint32_t>(buffer.size()), 0);
system_message, static_cast<uint32_t>(buf.size()), 0);
if (result != 0) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
basic_writer<char> w(out);
basic_writer<buffer> w(out);
w.write(message);
w.write(": ");
w.write(utf8_message);
......@@ -369,10 +349,10 @@ FMT_FUNC void internal::format_windows_error(
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
buf.resize(buf.size() * 2);
}
} FMT_CATCH(...) {}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
format_error_code(out, error_code, message);
}
#endif // FMT_USE_WINDOWS_H
......@@ -467,8 +447,6 @@ template int internal::char_traits<char>::format_float(
template wchar_t internal::thousands_sep(locale_provider *lp);
template class basic_context<wchar_t>;
template void basic_fixed_buffer<wchar_t>::grow(std::size_t);
template void internal::arg_map<wcontext>::init(const wformat_args &args);
......
......@@ -113,9 +113,6 @@
#endif
#ifndef FMT_USE_USER_DEFINED_LITERALS
// All compilers which support UDLs also support variadic templates. This
// makes the fmt::literals implementation easier. However, an explicit check
// for variadic templates is added here just in case.
// For Intel's compiler both it and the system gcc/msc must support UDLs.
# if (FMT_HAS_FEATURE(cxx_user_literals) || \
FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \
......@@ -261,7 +258,7 @@ class numeric_limits<fmt::internal::dummy_int> :
namespace fmt {
template <typename Char>
template <typename Range>
class basic_writer;
/** A formatting error such as invalid format string. */
......@@ -308,84 +305,7 @@ class locale;
class locale_provider {
public:
virtual ~locale_provider() {}
virtual locale locale();
};
/** A contiguous memory buffer with an optional growing ability. */
template <typename T>
class basic_buffer {
private:
FMT_DISALLOW_COPY_AND_ASSIGN(basic_buffer);
T *ptr_;
std::size_t size_;
std::size_t capacity_;
protected:
basic_buffer() FMT_NOEXCEPT : ptr_(0), size_(0), capacity_(0) {}
/** Sets the buffer data and capacity. */
void set(T* data, std::size_t capacity) FMT_NOEXCEPT {
ptr_ = data;
capacity_ = capacity;
}
/**
\rst
Increases the buffer capacity to hold at least *capacity* elements.
\endrst
*/
virtual void grow(std::size_t capacity) = 0;
public:
using value_type = T;
virtual ~basic_buffer() {}
T *begin() FMT_NOEXCEPT { return ptr_; }
T *end() FMT_NOEXCEPT { return ptr_ + capacity_; }
/** Returns the size of this buffer. */
std::size_t size() const FMT_NOEXCEPT { return size_; }
/** Returns the capacity of this buffer. */
std::size_t capacity() const FMT_NOEXCEPT { return capacity_; }
/** Returns a pointer to the buffer data. */
T *data() FMT_NOEXCEPT { return ptr_; }
/** Returns a pointer to the buffer data. */
const T *data() const FMT_NOEXCEPT { return ptr_; }
/**
Resizes the buffer. If T is a POD type new elements may not be initialized.
*/
void resize(std::size_t new_size) {
reserve(new_size);
size_ = new_size;
}
/**
\rst
Reserves space to store at least *capacity* elements.
\endrst
*/
void reserve(std::size_t capacity) {
if (capacity > capacity_)
grow(capacity);
}
void push_back(const T &value) {
reserve(size_ + 1);
ptr_[size_++] = value;
}
/** Appends data to the end of the buffer. */
template <typename U>
void append(const U *begin, const U *end);
T &operator[](std::size_t index) { return ptr_[index]; }
const T &operator[](std::size_t index) const { return ptr_[index]; }
virtual fmt::locale locale();
};
template <typename T>
......@@ -690,6 +610,33 @@ constexpr const Char *pointer_from(null_terminating_iterator<Char> it) {
return it.ptr_;
}
// A range that can grow dynamically.
template <typename Container>
class dynamic_range {
private:
Container &container_;
public:
using iterator = decltype(container_.begin());
using value_type = typename Container::value_type;
struct sentinel {
friend bool operator!=(sentinel, iterator) { return false; }
friend bool operator!=(iterator, sentinel) { return false; }
};
explicit dynamic_range(Container &c) : container_(c) {}
iterator begin() const { return container_.begin(); }
sentinel end() const { return sentinel(); }
friend iterator grow(dynamic_range r, size_t n) {
auto size = r.container_.size();
r.container_.resize(size + n);
return r.container_.begin() + size;
}
};
// Returns true if value is negative, false otherwise.
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
template <typename T>
......@@ -1255,11 +1202,8 @@ template <typename Context>
void arg_map<Context>::init(const basic_format_args<Context> &args) {
if (map_)
return;
map_ = new arg[args.max_size()];
typedef internal::named_arg<Context> NamedArg;
const NamedArg *named_arg = 0;
bool use_values =
args.type(MAX_PACKED_ARGS - 1) == internal::NONE;
map_ = new entry[args.max_size()];
bool use_values = args.type(MAX_PACKED_ARGS - 1) == internal::NONE;
if (use_values) {
for (unsigned i = 0;/*nothing*/; ++i) {
internal::type arg_type = args.type(i);
......@@ -1267,8 +1211,7 @@ void arg_map<Context>::init(const basic_format_args<Context> &args) {
case internal::NONE:
return;
case internal::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
push_back(arg{named_arg->name, *named_arg});
push_back(args.values_[i]);
break;
default:
break; // Do nothing.
......@@ -1277,19 +1220,15 @@ void arg_map<Context>::init(const basic_format_args<Context> &args) {
return;
}
for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) {
internal::type arg_type = args.type(i);
if (arg_type == internal::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].value_.pointer);
push_back(arg{named_arg->name, *named_arg});
}
if (args.type(i) == internal::NAMED_ARG)
push_back(args.args_[i].value_);
}
for (unsigned i = MAX_PACKED_ARGS; ; ++i) {
switch (args.args_[i].type_) {
case internal::NONE:
return;
case internal::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].value_.pointer);
push_back(arg{named_arg->name, *named_arg});
push_back(args.args_[i].value_);
break;
default:
break; // Do nothing.
......@@ -1434,15 +1373,13 @@ constexpr unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {
template <typename Char, typename Context>
class custom_formatter {
private:
basic_buffer<Char> &buffer_;
Context &ctx_;
public:
custom_formatter(basic_buffer<Char> &buffer, Context &ctx)
: buffer_(buffer), ctx_(ctx) {}
explicit custom_formatter(Context &ctx): ctx_(ctx) {}
bool operator()(typename basic_arg<Context>::handle h) {
h.format(buffer_, ctx_);
h.format(ctx_);
return true;
}
......@@ -2031,17 +1968,18 @@ struct format_type : std::integral_constant<bool, get_type<T>() != CUSTOM> {};
template <typename T, typename Enable = void>
struct format_enum : std::integral_constant<bool, std::is_enum<T>::value> {};
template <template <typename> class Handler, typename Spec, typename Char>
template <template <typename> class Handler, typename Spec, typename Context>
void handle_dynamic_spec(
Spec &value, arg_ref<Char> ref, basic_context<Char> &ctx) {
Spec &value, arg_ref<typename Context::char_type> ref, Context &ctx) {
using char_type = typename Context::char_type;
switch (ref.kind) {
case arg_ref<Char>::NONE:
case arg_ref<char_type>::NONE:
break;
case arg_ref<Char>::INDEX:
case arg_ref<char_type>::INDEX:
internal::set_dynamic_spec<Handler>(
value, ctx.get_arg(ref.index), ctx.error_handler());
break;
case arg_ref<Char>::NAME:
case arg_ref<char_type>::NAME:
internal::set_dynamic_spec<Handler>(
value, ctx.get_arg(ref.name), ctx.error_handler());
break;
......@@ -2050,15 +1988,17 @@ void handle_dynamic_spec(
} // namespace internal
/** The default argument formatter. */
template <typename Char>
class arg_formatter : public internal::arg_formatter_base<Char> {
template <typename Range>
class arg_formatter :
public internal::arg_formatter_base<typename Range::value_type> {
private:
basic_context<Char> &ctx_;
basic_context<Range> &ctx_;
typedef internal::arg_formatter_base<Char> Base;
using char_type = typename Range::value_type;
typedef internal::arg_formatter_base<char_type> Base;
public:
typedef typename Base::format_specs format_specs;
using format_specs = typename Base::format_specs;
/**
\rst
......@@ -2068,15 +2008,15 @@ class arg_formatter : public internal::arg_formatter_base<Char> {
format specifier information for standard argument types.
\endrst
*/
arg_formatter(basic_buffer<Char> &buffer, basic_context<Char> &ctx,
arg_formatter(basic_buffer<char_type> &buffer, basic_context<Range> &ctx,
format_specs &spec)
: internal::arg_formatter_base<Char>(buffer, spec), ctx_(ctx) {}
: internal::arg_formatter_base<char_type>(buffer, spec), ctx_(ctx) {}
using internal::arg_formatter_base<Char>::operator();
using internal::arg_formatter_base<char_type>::operator();
/** Formats an argument of a custom (user-defined) type. */
void operator()(typename basic_arg<basic_context<Char>>::handle handle) {
handle.format(this->writer().buffer(), ctx_);
void operator()(typename basic_arg<basic_context<Range>>::handle handle) {
handle.format(ctx_);
}
};
......@@ -2169,8 +2109,8 @@ class basic_writer {
using iterator = decltype(std::declval<Range>().begin());
// Output range.
iterator begin_;
decltype(std::declval<Range>().end()) end_;
internal::dynamic_range<Range> range_;
iterator out_;
std::unique_ptr<locale_provider> locale_;
......@@ -2185,17 +2125,9 @@ class basic_writer {
static char_type *get(char_type *p) { return p; }
#endif
template <typename Category>
void do_reserve(std::size_t, Category) {}
void do_reserve(std::size_t n, std::random_access_iterator_tag) {
(void)(begin_ + n);
}
// Attempts to reserve space for n characters in the output range.
void reserve(std::size_t n) {
using category = typename std::iterator_traits<iterator>::iterator_category;
do_reserve(n, category());
out_ = grow(range_, n);
}
// Writes a value in the format
......@@ -2218,12 +2150,15 @@ class basic_writer {
padding = spec.width() - size;
size = spec.width();
}
} else if (spec.precision() > num_digits) {
} else if (spec.precision() > static_cast<int>(num_digits)) {
size = prefix.size() + spec.precision();
padding = spec.precision() - num_digits;
fill = '0';
}
write_padded(size, spec, [prefix, fill, padding, f](auto &it) {
align_spec as = spec;
if (spec.align() == ALIGN_DEFAULT)
as.align_ = ALIGN_RIGHT;
write_padded(size, as, [prefix, fill, padding, f](auto &it) {
if (prefix.size() != 0)
it = std::uninitialized_copy_n(prefix.data(), prefix.size(), it);
it = std::uninitialized_fill_n(it, padding, fill);
......@@ -2242,8 +2177,8 @@ class basic_writer {
unsigned num_digits = internal::count_digits(abs_value);
reserve((is_negative ? 1 : 0) + num_digits);
if (is_negative)
*begin_++ = '-';
internal::format_decimal(begin_, abs_value, num_digits);
*out_++ = '-';
internal::format_decimal(out_, abs_value, num_digits);
}
// The handle_int_type_spec handler that writes an integer.
......@@ -2286,7 +2221,7 @@ class basic_writer {
unsigned num_digits = internal::count_digits(abs_value);
writer.write_int(num_digits, get_prefix(), spec,
[this, num_digits](auto &it) {
internal::format_decimal(it, abs_value, 0);
internal::format_decimal(it, abs_value, num_digits);
it += num_digits;
});
}
......@@ -2296,12 +2231,16 @@ class basic_writer {
prefix[prefix_size++] = '0';
prefix[prefix_size++] = spec.type();
}
writer.write_int(count_digits<4>(), get_prefix(), spec, [this](auto &it) {
unsigned num_digits = count_digits<4>();
writer.write_int(num_digits, get_prefix(), spec,
[this, num_digits](auto &it) {
it += num_digits;
auto out = it;
auto n = abs_value;
const char *digits = spec.type() == 'x' ?
"0123456789abcdef" : "0123456789ABCDEF";
do {
*it-- = digits[n & 0xf];
*--out = digits[n & 0xf];
} while ((n >>= 4) != 0);
});
}
......@@ -2311,35 +2250,46 @@ class basic_writer {
prefix[prefix_size++] = '0';
prefix[prefix_size++] = spec.type();
}
writer.write_int(count_digits<1>(), get_prefix(), spec, [this](auto &it) {
unsigned num_digits = count_digits<1>();
writer.write_int(num_digits, get_prefix(), spec,
[this, num_digits](auto &it) {
it += num_digits;
auto out = it;
auto n = abs_value;
do {
*it-- = static_cast<char_type>('0' + (n & 1));
*--out = static_cast<char_type>('0' + (n & 1));
} while ((n >>= 1) != 0);
});
}
void on_oct() {
if (spec.flag(HASH_FLAG))
unsigned num_digits = count_digits<3>();
if (spec.flag(HASH_FLAG) &&
spec.precision() <= static_cast<int>(num_digits)) {
// Octal prefix '0' is counted as a digit, so only add it if precision
// is not greater than the number of digits.
prefix[prefix_size++] = '0';
writer.write_int(count_digits<3>(), get_prefix(), spec, [this](auto &it) {
}
writer.write_int(num_digits, get_prefix(), spec,
[this, num_digits](auto &it) {
it += num_digits;
auto out = it;
auto n = abs_value;
do {
*it-- = static_cast<char_type>('0' + (n & 7));
*--out = static_cast<char_type>('0' + (n & 7));
} while ((n >>= 3) != 0);
});
}
void on_num() {
unsigned num_digits = internal::count_digits(abs_value);
char_type thousands_sep =
internal::thousands_sep<char_type>(writer.locale_.get());
basic_string_view<char_type> sep(&thousands_sep, 1);
unsigned size = static_cast<unsigned>(
num_digits + sep.size() * ((num_digits - 1) / 3));
char_type sep = internal::thousands_sep<char_type>(writer.locale_.get());
static constexpr unsigned SEP_SIZE = 1;
unsigned size = num_digits + SEP_SIZE * ((num_digits - 1) / 3);
writer.write_int(size, get_prefix(), spec, [this, size, sep](auto &it) {
internal::format_decimal(it, abs_value, 0,
internal::add_thousands_sep<char_type>(sep));
basic_string_view<char_type> s(&sep, SEP_SIZE);
internal::format_decimal(it, abs_value, size,
internal::add_thousands_sep<char_type>(s));
it += size;
});
}
......@@ -2385,7 +2335,7 @@ class basic_writer {
public:
/** Constructs a ``basic_writer`` object. */
explicit basic_writer(Range &r) : begin_(r.begin()), end_(r.end()) {}
explicit basic_writer(Range &r): range_(r), out_(r.begin()) {}
void write(int value) {
write_decimal(value);
......@@ -2405,7 +2355,9 @@ class basic_writer {
template <typename T, typename... FormatSpecs>
typename std::enable_if<std::is_integral<T>::value, void>::type
write(T value, FormatSpecs... specs) {
write_int(value, format_specs(specs...));
format_specs s(specs...);
s.align_ = ALIGN_RIGHT;
write_int(value, s);
}
void write(double value) {
......@@ -2424,12 +2376,14 @@ class basic_writer {
/** Writes a character to the buffer. */
void write(char value) {
*begin_++ = value;
reserve(1);
*out_++ = value;
}
void write(wchar_t value) {
internal::require_wchar<char_type>();
*begin_++ = value;
reserve(1);
*out_++ = value;
}
/**
......@@ -2438,12 +2392,14 @@ class basic_writer {
\endrst
*/
void write(string_view value) {
begin_ = std::uninitialized_copy(value.begin(), value.end(), begin_);
reserve(value.size());
out_ = std::uninitialized_copy(value.begin(), value.end(), out_);
}
void write(wstring_view value) {
internal::require_wchar<char_type>();
begin_ = std::uninitialized_copy(value.begin(), value.end(), begin_);
reserve(value.size());
out_ = std::uninitialized_copy(value.begin(), value.end(), out_);
}
template <typename... FormatSpecs>
......@@ -2459,22 +2415,22 @@ void basic_writer<Range>::write_padded(
unsigned width = spec.width();
if (width <= size) {
reserve(size);
return f(begin_);
return f(out_);
}
reserve(width);
char_type fill = internal::char_traits<char_type>::cast(spec.fill());
std::size_t padding = width - size;
if (spec.align() == ALIGN_RIGHT) {
begin_ = std::uninitialized_fill_n(begin_, padding, fill);
f(begin_);
out_ = std::uninitialized_fill_n(out_, padding, fill);
f(out_);
} else if (spec.align() == ALIGN_CENTER) {
std::size_t left_padding = padding / 2;
begin_ = std::uninitialized_fill_n(begin_, left_padding, fill);
f(begin_);
begin_ = std::uninitialized_fill_n(begin_, padding - left_padding, fill);
out_ = std::uninitialized_fill_n(out_, left_padding, fill);
f(out_);
out_ = std::uninitialized_fill_n(out_, padding - left_padding, fill);
} else {
f(begin_);
std::uninitialized_fill_n(begin_, padding, fill);
f(out_);
out_ = std::uninitialized_fill_n(out_, padding, fill);
}
}
......@@ -2549,41 +2505,29 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
sign = spec.flag(PLUS_FLAG) ? '+' : ' ';
}
if (internal::fputil::isnotanumber(value)) {
// Format NaN ourselves because sprintf's output is not consistent
// across platforms.
const char *nan = handler.upper ? "NAN" : "nan";
std::size_t nan_size = 3;
reserve(nan_size + (sign ? 1 : 0));
if (sign)
*begin_++ = sign;
begin_ = std::uninitialized_copy_n(nan, nan_size, begin_);
return;
}
auto write_inf_or_nan = [this, &spec, sign](const char *str) {
static constexpr std::size_t SIZE = 3;
write_padded(SIZE + (sign ? 1 : 0), spec, [sign, str](auto &it) {
if (sign)
*it++ = sign;
it = std::uninitialized_copy_n(str, SIZE, it);
});
};
if (internal::fputil::isinfinity(value)) {
// Format infinity ourselves because sprintf's output is not consistent
// across platforms.
const char *inf = handler.upper ? "INF" : "inf";
std::size_t inf_size = 3;
reserve(inf_size + (sign ? 1 : 0));
if (sign)
*begin_++ = sign;
begin_ = std::uninitialized_copy_n(inf, inf_size, begin_);
return;
}
// Format NaN and ininity ourselves because sprintf's output is not consistent
// across platforms.
if (internal::fputil::isnotanumber(value))
return write_inf_or_nan(handler.upper ? "NAN" : "nan");
if (internal::fputil::isinfinity(value))
return write_inf_or_nan(handler.upper ? "INF" : "inf");
// TODO: buffered_range that wraps a range and adds necessary buffering if the
// latter is not contiguous.
basic_memory_buffer<char_type> buffer;
std::size_t offset = 0;
unsigned width = spec.width();
if (sign) {
buffer.reserve(width > 1u ? width : 1u);
if (width > 0)
--width;
++offset;
}
// Build format string.
......@@ -2594,14 +2538,7 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
unsigned width_for_sprintf = width;
if (spec.flag(HASH_FLAG))
*format_ptr++ = '#';
if (spec.align() == ALIGN_CENTER) {
width_for_sprintf = 0;
} else {
if (spec.align() == ALIGN_LEFT)
*format_ptr++ = '-';
if (width != 0)
*format_ptr++ = '*';
}
width_for_sprintf = 0;
if (spec.precision() >= 0) {
*format_ptr++ = '.';
*format_ptr++ = '*';
......@@ -2616,33 +2553,46 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
unsigned n = 0;
char_type *start = 0;
for (;;) {
std::size_t buffer_size = buffer.capacity() - offset;
std::size_t buffer_size = buffer.capacity();
#if FMT_MSC_VER
// MSVC's vsnprintf_s doesn't work with zero size, so reserve
// space for at least one extra character to make the size non-zero.
// Note that the buffer's capacity may increase by more than 1.
if (buffer_size == 0) {
buffer.reserve(offset + 1);
buffer_size = buffer.capacity() - offset;
buffer.reserve(1);
buffer_size = buffer.capacity();
}
#endif
start = &buffer[offset];
start = &buffer[0];
int result = internal::char_traits<char_type>::format_float(
start, buffer_size, format, width_for_sprintf, spec.precision(), value);
if (result >= 0) {
n = internal::to_unsigned(result);
if (offset + n < buffer.capacity())
if (n < buffer.capacity())
break; // The buffer is large enough - continue with formatting.
buffer.reserve(offset + n + 1);
buffer.reserve(n + 1);
} else {
// If result is negative we ask to increase the capacity by at least 1,
// but as std::vector, the buffer grows exponentially.
buffer.reserve(buffer.capacity() + 1);
}
}
if (sign)
++n;
write_padded(n, spec, [n, sign, &buffer](auto &it) mutable {
align_spec as = spec;
if (spec.align() == ALIGN_NUMERIC) {
if (sign) {
reserve(1);
*out_++ = sign;
sign = 0;
--as.width_;
}
as.align_ = ALIGN_RIGHT;
} else {
if (spec.align() == ALIGN_DEFAULT)
as.align_ = ALIGN_RIGHT;
if (sign)
++n;
}
write_padded(n, as, [n, sign, &buffer](auto &it) mutable {
if (sign) {
*it++ = sign;
--n;
......@@ -2789,7 +2739,7 @@ class FormatInt {
// write a terminating null character.
template <typename T>
inline void format_decimal(char *&buffer, T value) {
typedef typename internal::int_traits<T>::main_type main_type;
using main_type = typename internal::int_traits<T>::main_type;
main_type abs_value = static_cast<main_type>(value);
if (internal::is_negative(value)) {
*buffer++ = '-';
......@@ -2867,13 +2817,14 @@ struct formatter<
return pointer_from(it);
}
void format(basic_buffer<Char> &buf, const T &val, basic_context<Char> &ctx) {
template <typename Range>
void format(const T &val, basic_context<Range> &ctx) {
internal::handle_dynamic_spec<internal::width_checker>(
specs_.width_, specs_.width_ref, ctx);
internal::handle_dynamic_spec<internal::precision_checker>(
specs_.precision_, specs_.precision_ref, ctx);
visit(arg_formatter<Char>(buf, ctx, specs_),
internal::make_arg<basic_context<Char>>(val));
visit(arg_formatter<Range>(ctx.range(), ctx, specs_),
internal::make_arg<basic_context<Range>>(val));
}
private:
......@@ -2912,7 +2863,8 @@ struct dynamic_formatter {
}
template <typename T>
void format(basic_buffer<Char> &buf, const T &val, basic_context<Char> &ctx) {
void format(basic_buffer<Char> &buf, const T &val,
basic_context<basic_buffer<Char>> &ctx) {
handle_specs(ctx);
struct null_handler : internal::error_handler {
void on_align(alignment) {}
......@@ -2938,12 +2890,13 @@ struct dynamic_formatter {
}
if (specs_.precision_ != -1)
checker.end_precision();
visit(arg_formatter<Char>(buf, ctx, specs_),
internal::make_arg<basic_context<Char>>(val));
visit(arg_formatter<basic_buffer<Char>>(buf, ctx, specs_),
internal::make_arg<basic_context<basic_buffer<Char>>>(val));
}
private:
void handle_specs(basic_context<Char> &ctx) {
template <typename Context>
void handle_specs(Context &ctx) {
internal::handle_dynamic_spec<internal::width_checker>(
specs_.width_, specs_.width_ref, ctx);
internal::handle_dynamic_spec<internal::precision_checker>(
......@@ -2953,14 +2906,14 @@ struct dynamic_formatter {
internal::dynamic_format_specs<Char> specs_;
};
template <typename Char>
inline typename basic_context<Char>::format_arg
basic_context<Char>::get_arg(basic_string_view<Char> name) {
template <typename Range>
typename basic_context<Range>::format_arg
basic_context<Range>::get_arg(basic_string_view<char_type> name) {
map_.init(this->args());
if (const format_arg *arg = map_.find(name))
return *arg;
this->on_error("argument not found");
return format_arg();
format_arg arg = map_.find(name);
if (arg.type() == internal::NONE)
this->on_error("argument not found");
return arg;
}
/** Formats arguments and writes the output to the buffer. */
......@@ -2972,7 +2925,7 @@ void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
struct handler : internal::error_handler {
handler(basic_buffer<Char> &b, basic_string_view<Char> str,
basic_format_args<Context> format_args)
: buffer(b), context(str, format_args) {}
: buffer(b), context(b, str, format_args) {}
void on_text(iterator begin, iterator end) {
buffer.append(pointer_from(begin), pointer_from(end));
......@@ -2990,7 +2943,7 @@ void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
void on_replacement_field(iterator it) {
context.advance_to(pointer_from(it));
using internal::custom_formatter;
if (visit(custom_formatter<Char, Context>(buffer, context), arg))
if (visit(custom_formatter<Char, Context>(context), arg))
return;
basic_format_specs<Char> specs;
visit(ArgFormatter(buffer, context, specs), arg);
......@@ -2999,7 +2952,7 @@ void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
iterator on_format_specs(iterator it) {
context.advance_to(pointer_from(it));
using internal::custom_formatter;
if (visit(custom_formatter<Char, Context>(buffer, context), arg))
if (visit(custom_formatter<Char, Context>(context), arg))
return iterator(context);
basic_format_specs<Char> specs;
using internal::specs_handler;
......@@ -3014,7 +2967,7 @@ void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
}
basic_buffer<Char> &buffer;
basic_context<Char> context;
Context context;
basic_arg<Context> arg;
};
parse_format_string(iterator(format_str.begin(), format_str.end()),
......@@ -3056,12 +3009,12 @@ void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
basic_format_args<Context> args);
inline void vformat_to(buffer &buf, string_view format_str, format_args args) {
vformat_to<arg_formatter<char>>(buf, format_str, args);
vformat_to<arg_formatter<buffer>>(buf, format_str, args);
}
inline void vformat_to(wbuffer &buf, wstring_view format_str,
wformat_args args) {
vformat_to<arg_formatter<wchar_t>>(buf, format_str, args);
vformat_to<arg_formatter<wbuffer>>(buf, format_str, args);
}
inline std::string vformat(string_view format_str, format_args args) {
......@@ -3124,7 +3077,7 @@ struct udl_arg {
const Char *str;
template <typename T>
named_arg<basic_context<Char>> operator=(T &&value) const {
named_arg<T, Char> operator=(T &&value) const {
return {str, std::forward<T>(value)};
}
};
......
/*
Formatting library for C++ - locale support
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
// Formatting library for C++ - locale support
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/format.h"
#include <locale>
......
/*
Formatting library for C++ - std::ostream support
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
// Formatting library for C++ - std::ostream support
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
......@@ -104,12 +102,12 @@ struct formatter<T, Char,
typename std::enable_if<!internal::format_type<T>::value>::type>
: formatter<basic_string_view<Char>, Char> {
void format(basic_buffer<Char> &buf, const T &value,
basic_context<Char> &ctx) {
template <typename Context>
void format(const T &value, Context &ctx) {
basic_memory_buffer<Char> buffer;
internal::format_value(buffer, value);
basic_string_view<Char> str(buffer.data(), buffer.size());
formatter<basic_string_view<Char>, Char>::format(buf, str, ctx);
formatter<basic_string_view<Char>, Char>::format(str, ctx);
}
};
......
/*
A C++ interface to POSIX functions.
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
// A C++ interface to POSIX functions.
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
// Disable bogus MSVC warnings.
#ifndef _CRT_SECURE_NO_WARNINGS
......
/*
A C++ interface to POSIX functions.
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
// A C++ interface to POSIX functions.
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_POSIX_H_
#define FMT_POSIX_H_
......
/*
Formatting library for C++
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_PRINTF_H_
#define FMT_PRINTF_H_
......@@ -200,11 +198,10 @@ class PrintfWidthHandler {
};
} // namespace internal
template <typename Char>
template <typename Range>
class printf_arg_formatter;
template <typename Char,
typename ArgFormatter = printf_arg_formatter<Char> >
template <typename Range, typename ArgFormatter = printf_arg_formatter<Range>>
class printf_context;
/**
......@@ -212,20 +209,22 @@ class printf_context;
The ``printf`` argument formatter.
\endrst
*/
template <typename Char>
class printf_arg_formatter : public internal::arg_formatter_base<Char> {
template <typename Range>
class printf_arg_formatter :
public internal::arg_formatter_base<typename Range::value_type> {
private:
printf_context<Char>& context_;
printf_context<Range>& context_;
void write_null_pointer() {
this->spec().type_ = 0;
this->write("(nil)");
}
typedef internal::arg_formatter_base<Char> Base;
using char_type = typename Range::value_type;
using base = internal::arg_formatter_base<char_type>;
public:
typedef typename Base::format_specs format_specs;
typedef typename base::format_specs format_specs;
/**
\rst
......@@ -234,11 +233,11 @@ class printf_arg_formatter : public internal::arg_formatter_base<Char> {
specifier information for standard argument types.
\endrst
*/
printf_arg_formatter(
basic_buffer<Char> &buffer, format_specs &spec, printf_context<Char> &ctx)
: internal::arg_formatter_base<Char>(buffer, spec), context_(ctx) {}
printf_arg_formatter(basic_buffer<char_type> &buffer, format_specs &spec,
printf_context<Range> &ctx)
: internal::arg_formatter_base<char_type>(buffer, spec), context_(ctx) {}
using Base::operator();
using base::operator();
/** Formats an argument of type ``bool``. */
void operator()(bool value) {
......@@ -250,19 +249,19 @@ class printf_arg_formatter : public internal::arg_formatter_base<Char> {
}
/** Formats a character. */
void operator()(Char value) {
void operator()(char_type value) {
format_specs &fmt_spec = this->spec();
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
return (*this)(static_cast<int>(value));
fmt_spec.flags_ = 0;
fmt_spec.align_ = ALIGN_RIGHT;
Base::operator()(value);
base::operator()(value);
}
/** Formats a null-terminated C string. */
void operator()(const char *value) {
if (value)
Base::operator()(value);
base::operator()(value);
else if (this->spec().type_ == 'p')
write_null_pointer();
else
......@@ -272,44 +271,44 @@ class printf_arg_formatter : public internal::arg_formatter_base<Char> {
/** Formats a pointer. */
void operator()(const void *value) {
if (value)
return Base::operator()(value);
return base::operator()(value);
this->spec().type_ = 0;
write_null_pointer();
}
/** Formats an argument of a custom (user-defined) type. */
void operator()(typename basic_arg<printf_context<Char>>::handle handle) {
handle.format(this->writer().buffer(), context_);
void operator()(typename basic_arg<printf_context<Range>>::handle handle) {
handle.format(context_);
}
};
template <typename T, typename Char = char>
template <typename T>
struct printf_formatter {
template <typename ParseContext>
const Char *parse(ParseContext& ctx) { return ctx.begin(); }
auto parse(ParseContext& ctx) { return ctx.begin(); }
void format(basic_buffer<Char> &buf, const T &value, printf_context<Char> &) {
internal::format_value(buf, value);
template <typename Range>
void format(const T &value, printf_context<Range> &ctx) {
internal::format_value(ctx.range(), value);
}
};
/** This template formats data and writes the output to a writer. */
template <typename Char, typename ArgFormatter>
template <typename Range, typename ArgFormatter>
class printf_context :
private internal::context_base<
Char, printf_context<Char, ArgFormatter>> {
private internal::context_base<Range, printf_context<Range, ArgFormatter>> {
public:
/** The character type for the output. */
using char_type = Char;
using char_type = typename Range::value_type;
template <typename T>
using formatter_type = printf_formatter<T>;
private:
typedef internal::context_base<Char, printf_context> Base;
typedef typename Base::format_arg format_arg;
typedef basic_format_specs<Char> format_specs;
typedef internal::null_terminating_iterator<Char> iterator;
typedef internal::context_base<Range, printf_context> Base;
using format_arg = typename Base::format_arg;
using format_specs = basic_format_specs<char_type>;
using iterator = internal::null_terminating_iterator<char_type>;
void parse_flags(format_specs &spec, iterator &it);
......@@ -330,18 +329,19 @@ class printf_context :
appropriate lifetimes.
\endrst
*/
printf_context(basic_string_view<Char> format_str,
printf_context(Range &range, basic_string_view<char_type> format_str,
basic_format_args<printf_context> args)
: Base(format_str, args) {}
: Base(range, format_str, args) {}
using Base::parse_context;
using Base::range;
/** Formats stored arguments and writes the output to the buffer. */
FMT_API void format(basic_buffer<Char> &buffer);
/** Formats stored arguments and writes the output to the range. */
FMT_API void format();
};
template <typename Char, typename AF>
void printf_context<Char, AF>::parse_flags(format_specs &spec, iterator &it) {
template <typename Range, typename AF>
void printf_context<Range, AF>::parse_flags(format_specs &spec, iterator &it) {
for (;;) {
switch (*it++) {
case '-':
......@@ -366,20 +366,20 @@ void printf_context<Char, AF>::parse_flags(format_specs &spec, iterator &it) {
}
}
template <typename Char, typename AF>
typename printf_context<Char, AF>::format_arg printf_context<Char, AF>::get_arg(
iterator it, unsigned arg_index) {
template <typename Range, typename AF>
typename printf_context<Range, AF>::format_arg
printf_context<Range, AF>::get_arg(iterator it, unsigned arg_index) {
(void)it;
if (arg_index == std::numeric_limits<unsigned>::max())
return this->do_get_arg(this->next_arg_id());
return Base::get_arg(arg_index - 1);
}
template <typename Char, typename AF>
unsigned printf_context<Char, AF>::parse_header(
template <typename Range, typename AF>
unsigned printf_context<Range, AF>::parse_header(
iterator &it, format_specs &spec) {
unsigned arg_index = std::numeric_limits<unsigned>::max();
Char c = *it;
char_type c = *it;
if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s).
......@@ -406,19 +406,21 @@ unsigned printf_context<Char, AF>::parse_header(
spec.width_ = parse_nonnegative_int(it, eh);
} else if (*it == '*') {
++it;
spec.width_ = visit(internal::PrintfWidthHandler<Char>(spec), get_arg(it));
spec.width_ =
visit(internal::PrintfWidthHandler<char_type>(spec), get_arg(it));
}
return arg_index;
}
template <typename Char, typename AF>
void printf_context<Char, AF>::format(basic_buffer<Char> &buffer) {
template <typename Range, typename AF>
void printf_context<Range, AF>::format() {
Range &buffer = this->range();
Base &base = *this;
auto start = iterator(base);
auto it = start;
using internal::pointer_from;
while (*it) {
Char c = *it++;
char_type c = *it++;
if (c != '%') continue;
if (*it == c) {
buffer.append(pointer_from(start), pointer_from(it));
......@@ -501,7 +503,7 @@ void printf_context<Char, AF>::format(basic_buffer<Char> &buffer) {
break;
case 'c':
// TODO: handle wchar_t
visit(internal::CharConverter<printf_context<Char, AF>>(arg), arg);
visit(internal::CharConverter<printf_context<Range, AF>>(arg), arg);
break;
}
}
......@@ -516,11 +518,11 @@ void printf_context<Char, AF>::format(basic_buffer<Char> &buffer) {
template <typename Char>
void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
basic_format_args<printf_context<Char>> args) {
printf_context<Char>(format, args).format(buf);
basic_format_args<printf_context<basic_buffer<Char>>> args) {
printf_context<basic_buffer<Char>>(buf, format, args).format();
}
typedef basic_format_args<printf_context<char>> printf_args;
typedef basic_format_args<printf_context<buffer>> printf_args;
inline std::string vsprintf(string_view format, printf_args args) {
memory_buffer buffer;
......@@ -539,11 +541,11 @@ inline std::string vsprintf(string_view format, printf_args args) {
*/
template <typename... Args>
inline std::string sprintf(string_view format_str, const Args & ... args) {
return vsprintf(format_str, make_args<printf_context<char>>(args...));
return vsprintf(format_str, make_args<printf_context<buffer>>(args...));
}
inline std::wstring vsprintf(
wstring_view format, basic_format_args<printf_context<wchar_t>> args) {
wstring_view format, basic_format_args<printf_context<wbuffer>> args) {
wmemory_buffer buffer;
printf(buffer, format, args);
return to_string(buffer);
......@@ -551,7 +553,7 @@ inline std::wstring vsprintf(
template <typename... Args>
inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
auto vargs = make_args<printf_context<wchar_t>>(args...);
auto vargs = make_args<printf_context<wbuffer>>(args...);
return vsprintf(format_str, vargs);
}
......@@ -574,7 +576,7 @@ inline int vfprintf(std::FILE *f, string_view format, printf_args args) {
*/
template <typename... Args>
inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
auto vargs = make_args<printf_context<char>>(args...);
auto vargs = make_args<printf_context<buffer>>(args...);
return vfprintf(f, format_str, vargs);
}
......@@ -593,10 +595,11 @@ inline int vprintf(string_view format, printf_args args) {
*/
template <typename... Args>
inline int printf(string_view format_str, const Args & ... args) {
return vprintf(format_str, make_args<printf_context<char>>(args...));
return vprintf(format_str, make_args<printf_context<buffer>>(args...));
}
inline int vfprintf(std::ostream &os, string_view format_str, printf_args args) {
inline int vfprintf(std::ostream &os, string_view format_str,
printf_args args) {
memory_buffer buffer;
printf(buffer, format_str, args);
internal::write(os, buffer);
......@@ -615,7 +618,7 @@ inline int vfprintf(std::ostream &os, string_view format_str, printf_args args)
template <typename... Args>
inline int fprintf(std::ostream &os, string_view format_str,
const Args & ... args) {
auto vargs = make_args<printf_context<char>>(args...);
auto vargs = make_args<printf_context<buffer>>(args...);
return vfprintf(os, format_str, vargs);
}
} // namespace fmt
......
/*
Formatting library for C++ - string utilities
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
// Formatting library for C++ - string utilities
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_STRING_H_
#define FMT_STRING_H_
......
/*
Formatting library for C++ - time formatting
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
// Formatting library for C++ - time formatting
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_TIME_H_
#define FMT_TIME_H_
......@@ -32,7 +30,8 @@ struct formatter<std::tm> {
return pointer_from(end);
}
void format(buffer &buf, const std::tm &tm, context &) {
void format(const std::tm &tm, context &ctx) {
buffer &buf = ctx.range();
std::size_t start = buf.size();
for (;;) {
std::size_t size = buf.capacity() - start;
......
......@@ -14,18 +14,18 @@ using fmt::printf_arg_formatter;
// A custom argument formatter that doesn't print `-` for floating-point values
// rounded to 0.
class CustomArgFormatter : public fmt::arg_formatter<char> {
class CustomArgFormatter : public fmt::arg_formatter<fmt::buffer> {
public:
CustomArgFormatter(fmt::buffer &buf, fmt::basic_context<char> &ctx,
CustomArgFormatter(fmt::buffer &buf, fmt::basic_context<fmt::buffer> &ctx,
fmt::format_specs &s)
: fmt::arg_formatter<char>(buf, ctx, s) {}
: fmt::arg_formatter<fmt::buffer>(buf, ctx, s) {}
using fmt::arg_formatter<char>::operator();
using fmt::arg_formatter<fmt::buffer>::operator();
void operator()(double value) {
if (round(value * pow(10, spec().precision())) == 0)
value = 0;
fmt::arg_formatter<char>::operator()(value);
fmt::arg_formatter<fmt::buffer>::operator()(value);
}
};
......
......@@ -31,7 +31,6 @@
#include <cmath>
#include <cstring>
#include <memory>
#include <type_traits>
#include <stdint.h>
#include "gmock/gmock.h"
......@@ -91,7 +90,7 @@ template <typename Char, typename T>
fmt::basic_memory_buffer<Char> buffer;
fmt::basic_writer<fmt::basic_buffer<Char>> writer(buffer);
writer.write(value);
std::basic_string<Char> actual = writer.str();
std::basic_string<Char> actual = to_string(buffer);
std::basic_string<Char> expected;
std_format(value, expected);
if (expected == actual)
......@@ -149,19 +148,11 @@ TEST(WriterTest, NotCopyAssignable) {
EXPECT_FALSE(std::is_copy_assignable<basic_writer<fmt::buffer>>::value);
}
TEST(WriterTest, Ctor) {
memory_buffer buf;
fmt::basic_writer<fmt::buffer> w(buf);
EXPECT_EQ(0u, w.size());
EXPECT_STREQ("", w.c_str());
EXPECT_EQ("", w.str());
}
TEST(WriterTest, Data) {
memory_buffer buf;
fmt::basic_writer<fmt::buffer> w(buf);
w.write(42);
EXPECT_EQ("42", std::string(w.data(), w.size()));
EXPECT_EQ("42", to_string(buf));
}
TEST(WriterTest, WriteInt) {
......@@ -224,7 +215,9 @@ TEST(WriterTest, WriteDoubleWithFilledBuffer) {
for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i)
writer.write(' ');
writer.write(1.2);
EXPECT_STREQ("1.2", writer.c_str() + fmt::internal::INLINE_BUFFER_SIZE);
fmt::string_view sv(buf.data(), buf.size());
sv.remove_prefix(fmt::internal::INLINE_BUFFER_SIZE);
EXPECT_EQ("1.2", sv);
}
TEST(WriterTest, WriteChar) {
......@@ -239,31 +232,29 @@ TEST(WriterTest, WriteString) {
CHECK_WRITE_CHAR("abc");
CHECK_WRITE_WCHAR("abc");
// The following line shouldn't compile:
//MemoryWriter() << L"abc";
//std::declval<fmt::basic_writer<fmt::buffer>>().write(L"abc");
}
TEST(WriterTest, WriteWideString) {
CHECK_WRITE_WCHAR(L"abc");
// The following line shouldn't compile:
//fmt::WMemoryWriter() << "abc";
//std::declval<fmt::basic_writer<fmt::wbuffer>>().write("abc");
}
template <typename... T>
std::string write_str(T... args) {
memory_buffer buf;
fmt::basic_writer<fmt::buffer> writer(buf);
using namespace fmt;
writer.write(args...);
return writer.str();
return to_string(buf);
}
template <typename... T>
std::wstring write_wstr(T... args) {
wmemory_buffer buf;
fmt::basic_writer<fmt::wbuffer> writer(buf);
using namespace fmt;
writer.write(args...);
return writer.str();
return to_string(buf);
}
TEST(WriterTest, bin) {
......@@ -350,17 +341,20 @@ TEST(WriterTest, pad) {
EXPECT_EQ(" 33", write_str(33ll, width=7));
EXPECT_EQ(" 44", write_str(44ull, width=7));
memory_buffer buf;
fmt::basic_writer<fmt::buffer> w(buf);
w.clear();
w.write(42, fmt::width=5, fmt::fill='0');
EXPECT_EQ("00042", w.str());
w.clear();
w << Date(2012, 12, 9);
EXPECT_EQ("2012-12-9", w.str());
w.clear();
w << iso8601(Date(2012, 1, 9));
EXPECT_EQ("2012-01-09", w.str());
EXPECT_EQ("00042", write_str(42, fmt::width=5, fmt::fill='0'));
{
memory_buffer buf;
fmt::basic_writer<fmt::buffer> w(buf);
w << Date(2012, 12, 9);
EXPECT_EQ("2012-12-9", to_string(buf));
}
{
memory_buffer buf;
fmt::basic_writer<fmt::buffer> w(buf);
w << iso8601(Date(2012, 1, 9));
EXPECT_EQ("2012-01-09", to_string(buf));
}
}
TEST(WriterTest, PadString) {
......@@ -1228,8 +1222,8 @@ struct formatter<Date> {
return it;
}
void format(buffer &buf, const Date &d, context &) {
format_to(buf, "{}-{}-{}", d.year(), d.month(), d.day());
void format(const Date &d, context &ctx) {
format_to(ctx.range(), "{}-{}-{}", d.year(), d.month(), d.day());
}
};
}
......@@ -1245,8 +1239,8 @@ class Answer {};
namespace fmt {
template <>
struct formatter<Answer> : formatter<int> {
void format(fmt::buffer &buf, Answer, fmt::context &ctx) {
formatter<int>::format(buf, 42, ctx);
void format(Answer, fmt::context &ctx) {
formatter<int>::format(42, ctx);
}
};
}
......@@ -1535,11 +1529,11 @@ struct variant {
namespace fmt {
template <>
struct formatter<variant> : dynamic_formatter<> {
void format(buffer& buf, variant value, context& ctx) {
void format(variant value, context& ctx) {
if (value.type == variant::INT)
dynamic_formatter::format(buf, 42, ctx);
dynamic_formatter::format(ctx.range(), 42, ctx);
else
dynamic_formatter::format(buf, "foo", ctx);
dynamic_formatter::format(ctx.range(), "foo", ctx);
}
};
}
......
......@@ -58,14 +58,14 @@ TEST(OStreamTest, Enum) {
EXPECT_EQ("0", fmt::format("{}", A));
}
struct TestArgFormatter : fmt::arg_formatter<char> {
struct TestArgFormatter : fmt::arg_formatter<fmt::buffer> {
TestArgFormatter(fmt::buffer &buf, fmt::context &ctx, fmt::format_specs &s)
: fmt::arg_formatter<char>(buf, ctx, s) {}
: fmt::arg_formatter<fmt::buffer>(buf, ctx, s) {}
};
TEST(OStreamTest, CustomArg) {
fmt::memory_buffer buffer;
fmt::context ctx("", fmt::format_args());
fmt::context ctx(buffer, "", fmt::format_args());
fmt::format_specs spec;
TestArgFormatter af(buffer, ctx, spec);
visit(af, fmt::internal::make_arg<fmt::context>(TestEnum()));
......
......@@ -81,9 +81,9 @@ struct formatter<Test, Char> {
return ctx.begin();
}
void format(basic_buffer<Char> &b, Test, basic_context<Char> &) {
void format(Test, basic_context<basic_buffer<Char>> &ctx) {
const Char *test = "test";
b.append(test, test + std::strlen(test));
ctx.range().append(test, test + std::strlen(test));
}
};
}
......@@ -442,7 +442,7 @@ struct CustomContext {
return ctx.begin();
}
void format(fmt::buffer &, const T &, CustomContext& ctx) {
void format(const T &, CustomContext& ctx) {
ctx.called = true;
}
};
......@@ -456,8 +456,7 @@ TEST(UtilTest, MakeValueWithCustomFormatter) {
::Test t;
fmt::internal::value<CustomContext> arg(t);
CustomContext ctx = {false};
fmt::memory_buffer buffer;
arg.custom.format(buffer, &t, ctx);
arg.custom.format(&t, ctx);
EXPECT_TRUE(ctx.called);
}
......@@ -518,7 +517,8 @@ VISIT_TYPE(float, double);
#define CHECK_ARG_(Char, expected, value) { \
testing::StrictMock<MockVisitor<decltype(expected)>> visitor; \
EXPECT_CALL(visitor, visit(expected)); \
fmt::visit(visitor, make_arg<fmt::basic_context<Char>>(value)); \
fmt::visit(visitor, \
make_arg<fmt::basic_context<basic_buffer<Char>>>(value)); \
}
#define CHECK_ARG(value) { \
......@@ -596,8 +596,8 @@ TEST(UtilTest, CustomArg) {
testing::StrictMock<visitor> v;
EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke([&](handle h) {
fmt::memory_buffer buffer;
fmt::context ctx("", fmt::format_args());
h.format(buffer, ctx);
fmt::context ctx(buffer, "", fmt::format_args());
h.format(ctx);
EXPECT_EQ("test", std::string(buffer.data(), buffer.size()));
return visitor::Result();
}));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment