Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
fmt
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
fmt
Commits
c0954453
Commit
c0954453
authored
Jan 06, 2018
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Replace buffer with range
parent
c3d6c5fc
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
544 additions
and
555 deletions
+544
-555
include/fmt/core.h
include/fmt/core.h
+199
-127
include/fmt/format.cc
include/fmt/format.cc
+13
-35
include/fmt/format.h
include/fmt/format.h
+177
-224
include/fmt/locale.h
include/fmt/locale.h
+6
-8
include/fmt/ostream.h
include/fmt/ostream.h
+9
-11
include/fmt/posix.cc
include/fmt/posix.cc
+6
-8
include/fmt/posix.h
include/fmt/posix.h
+6
-8
include/fmt/printf.h
include/fmt/printf.h
+68
-65
include/fmt/string.h
include/fmt/string.h
+6
-8
include/fmt/time.h
include/fmt/time.h
+8
-9
test/custom-formatter-test.cc
test/custom-formatter-test.cc
+5
-5
test/format-test.cc
test/format-test.cc
+30
-36
test/ostream-test.cc
test/ostream-test.cc
+3
-3
test/util-test.cc
test/util-test.cc
+8
-8
No files found.
include/fmt/core.h
View file @
c0954453
/*
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
B
ase
::
format_arg
;
using
B
ase
::
get_arg
;
using
format_arg
=
typename
b
ase
::
format_arg
;
using
b
ase
::
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
<
wcontex
t
>
arg
(
wstring_view
name
,
const
T
&
arg
)
{
return
internal
::
named_arg
<
wcontex
t
>
(
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_UNDEFIN
ED
;
template
<
typename
Context
>
void
arg
(
wstring_view
,
internal
::
named_arg
<
Context
>
)
FMT_DELETED_OR_UNDEFIN
ED
;
template
<
typename
T
>
void
arg
(
string_view
,
internal
::
named_arg
<
T
,
char
>
)
FMT_DELET
ED
;
template
<
typename
T
>
void
arg
(
wstring_view
,
internal
::
named_arg
<
T
,
wchar_t
>
)
FMT_DELET
ED
;
enum
Color
{
BLACK
,
RED
,
GREEN
,
YELLOW
,
BLUE
,
MAGENTA
,
CYAN
,
WHITE
};
...
...
include/fmt/format.cc
View file @
c0954453
/*
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
buf
fer
;
buf
fer
.
resize
(
INLINE_BUFFER_SIZE
);
wmemory_buffer
buf
;
buf
.
resize
(
INLINE_BUFFER_SIZE
);
for
(;;)
{
wchar_t
*
system_message
=
&
buf
fer
[
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
>
(
buf
fer
.
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
<
cha
r
>
w
(
out
);
basic_writer
<
buffe
r
>
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.
buf
fer
.
resize
(
buffer
.
size
()
*
2
);
buf
.
resize
(
buf
.
size
()
*
2
);
}
}
FMT_CATCH
(...)
{}
f
mt
::
format_error_code
(
out
,
error_code
,
message
);
// 'fmt::' is for bcc32.
f
ormat_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
);
...
...
include/fmt/format.h
View file @
c0954453
...
...
@@ -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
C
har
>
template
<
template
<
typename
>
class
Handler
,
typename
Spec
,
typename
C
ontext
>
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.
i
terator
begin
_
;
decltype
(
std
::
declval
<
Range
>
().
end
())
end
_
;
i
nternal
::
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
<
cha
r
>>
(
buf
,
format_str
,
args
);
vformat_to
<
arg_formatter
<
buffe
r
>>
(
buf
,
format_str
,
args
);
}
inline
void
vformat_to
(
wbuffer
&
buf
,
wstring_view
format_str
,
wformat_args
args
)
{
vformat_to
<
arg_formatter
<
w
char_t
>>
(
buf
,
format_str
,
args
);
vformat_to
<
arg_formatter
<
w
buffer
>>
(
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
)};
}
};
...
...
include/fmt/locale.h
View file @
c0954453
/*
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>
...
...
include/fmt/ostream.h
View file @
c0954453
/*
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
);
}
};
...
...
include/fmt/posix.cc
View file @
c0954453
/*
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
...
...
include/fmt/posix.h
View file @
c0954453
/*
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_
...
...
include/fmt/printf.h
View file @
c0954453
/*
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
B
ase
::
format_specs
format_specs
;
typedef
typename
b
ase
::
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
B
ase
::
operator
();
using
b
ase
::
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
;
B
ase
::
operator
()(
value
);
b
ase
::
operator
()(
value
);
}
/** Formats a null-terminated C string. */
void
operator
()(
const
char
*
value
)
{
if
(
value
)
B
ase
::
operator
()(
value
);
b
ase
::
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
B
ase
::
operator
()(
value
);
return
b
ase
::
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
<
cha
r
>>
printf_args
;
typedef
basic_format_args
<
printf_context
<
buffe
r
>>
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
<
cha
r
>>
(
args
...));
return
vsprintf
(
format_str
,
make_args
<
printf_context
<
buffe
r
>>
(
args
...));
}
inline
std
::
wstring
vsprintf
(
wstring_view
format
,
basic_format_args
<
printf_context
<
w
char_t
>>
args
)
{
wstring_view
format
,
basic_format_args
<
printf_context
<
w
buffer
>>
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
<
w
char_t
>>
(
args
...);
auto
vargs
=
make_args
<
printf_context
<
w
buffer
>>
(
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
<
cha
r
>>
(
args
...);
auto
vargs
=
make_args
<
printf_context
<
buffe
r
>>
(
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
<
cha
r
>>
(
args
...));
return
vprintf
(
format_str
,
make_args
<
printf_context
<
buffe
r
>>
(
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
<
cha
r
>>
(
args
...);
auto
vargs
=
make_args
<
printf_context
<
buffe
r
>>
(
args
...);
return
vfprintf
(
os
,
format_str
,
vargs
);
}
}
// namespace fmt
...
...
include/fmt/string.h
View file @
c0954453
/*
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_
...
...
include/fmt/time.h
View file @
c0954453
/*
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
;
...
...
test/custom-formatter-test.cc
View file @
c0954453
...
...
@@ -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
<
cha
r
>
{
class
CustomArgFormatter
:
public
fmt
::
arg_formatter
<
fmt
::
buffe
r
>
{
public:
CustomArgFormatter
(
fmt
::
buffer
&
buf
,
fmt
::
basic_context
<
cha
r
>
&
ctx
,
CustomArgFormatter
(
fmt
::
buffer
&
buf
,
fmt
::
basic_context
<
fmt
::
buffe
r
>
&
ctx
,
fmt
::
format_specs
&
s
)
:
fmt
::
arg_formatter
<
cha
r
>
(
buf
,
ctx
,
s
)
{}
:
fmt
::
arg_formatter
<
fmt
::
buffe
r
>
(
buf
,
ctx
,
s
)
{}
using
fmt
::
arg_formatter
<
cha
r
>::
operator
();
using
fmt
::
arg_formatter
<
fmt
::
buffe
r
>::
operator
();
void
operator
()(
double
value
)
{
if
(
round
(
value
*
pow
(
10
,
spec
().
precision
()))
==
0
)
value
=
0
;
fmt
::
arg_formatter
<
cha
r
>::
operator
()(
value
);
fmt
::
arg_formatter
<
fmt
::
buffe
r
>::
operator
()(
value
);
}
};
...
...
test/format-test.cc
View file @
c0954453
...
...
@@ -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
);
}
};
}
...
...
test/ostream-test.cc
View file @
c0954453
...
...
@@ -58,14 +58,14 @@ TEST(OStreamTest, Enum) {
EXPECT_EQ
(
"0"
,
fmt
::
format
(
"{}"
,
A
));
}
struct
TestArgFormatter
:
fmt
::
arg_formatter
<
cha
r
>
{
struct
TestArgFormatter
:
fmt
::
arg_formatter
<
fmt
::
buffe
r
>
{
TestArgFormatter
(
fmt
::
buffer
&
buf
,
fmt
::
context
&
ctx
,
fmt
::
format_specs
&
s
)
:
fmt
::
arg_formatter
<
cha
r
>
(
buf
,
ctx
,
s
)
{}
:
fmt
::
arg_formatter
<
fmt
::
buffe
r
>
(
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
()));
...
...
test/util-test.cc
View file @
c0954453
...
...
@@ -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
();
}));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment