Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
S
spdlog
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
spdlog
Commits
e060bbf3
Commit
e060bbf3
authored
Dec 22, 2015
by
gabime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
astyle
parent
a1e25cdb
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
849 additions
and
428 deletions
+849
-428
spdlog-async.cpp
bench/spdlog-async.cpp
+0
-0
format.h
include/spdlog/details/format.h
+849
-428
No files found.
bench/spdlog-async.cpp
View file @
e060bbf3
include/spdlog/details/format.h
View file @
e060bbf3
...
@@ -80,10 +80,13 @@ typedef long long intmax_t;
...
@@ -80,10 +80,13 @@ typedef long long intmax_t;
#ifdef _MSC_VER
#ifdef _MSC_VER
# include <intrin.h> // _BitScanReverse, _BitScanReverse64
# include <intrin.h> // _BitScanReverse, _BitScanReverse64
namespace
fmt
{
namespace
fmt
namespace
internal
{
{
namespace
internal
{
# pragma intrinsic(_BitScanReverse)
# pragma intrinsic(_BitScanReverse)
inline
uint32_t
clz
(
uint32_t
x
)
{
inline
uint32_t
clz
(
uint32_t
x
)
{
unsigned
long
r
=
0
;
unsigned
long
r
=
0
;
_BitScanReverse
(
&
r
,
x
);
_BitScanReverse
(
&
r
,
x
);
return
31
-
r
;
return
31
-
r
;
...
@@ -94,7 +97,8 @@ inline uint32_t clz(uint32_t x) {
...
@@ -94,7 +97,8 @@ inline uint32_t clz(uint32_t x) {
# pragma intrinsic(_BitScanReverse64)
# pragma intrinsic(_BitScanReverse64)
# endif
# endif
inline
uint32_t
clzll
(
uint64_t
x
)
{
inline
uint32_t
clzll
(
uint64_t
x
)
{
unsigned
long
r
=
0
;
unsigned
long
r
=
0
;
# ifdef _WIN64
# ifdef _WIN64
_BitScanReverse64
(
&
r
,
x
);
_BitScanReverse64
(
&
r
,
x
);
...
@@ -254,11 +258,15 @@ inline uint32_t clzll(uint64_t x) {
...
@@ -254,11 +258,15 @@ inline uint32_t clzll(uint64_t x) {
# define FMT_ASSERT(condition, message) assert((condition) && message)
# define FMT_ASSERT(condition, message) assert((condition) && message)
#endif
#endif
namespace
fmt
{
namespace
fmt
namespace
internal
{
{
struct
DummyInt
{
namespace
internal
{
struct
DummyInt
{
int
data
[
2
];
int
data
[
2
];
operator
int
()
const
{
operator
int
()
const
{
return
0
;
return
0
;
}
}
};
};
...
@@ -266,51 +274,62 @@ typedef std::numeric_limits<fmt::internal::DummyInt> FPUtil;
...
@@ -266,51 +274,62 @@ typedef std::numeric_limits<fmt::internal::DummyInt> FPUtil;
// Dummy implementations of system functions such as signbit and ecvt called
// Dummy implementations of system functions such as signbit and ecvt called
// if the latter are not available.
// if the latter are not available.
inline
DummyInt
signbit
(...)
{
inline
DummyInt
signbit
(...)
{
return
DummyInt
();
return
DummyInt
();
}
}
inline
DummyInt
_ecvt_s
(...)
{
inline
DummyInt
_ecvt_s
(...)
{
return
DummyInt
();
return
DummyInt
();
}
}
inline
DummyInt
isinf
(...)
{
inline
DummyInt
isinf
(...)
{
return
DummyInt
();
return
DummyInt
();
}
}
inline
DummyInt
_finite
(...)
{
inline
DummyInt
_finite
(...)
{
return
DummyInt
();
return
DummyInt
();
}
}
inline
DummyInt
isnan
(...)
{
inline
DummyInt
isnan
(...)
{
return
DummyInt
();
return
DummyInt
();
}
}
inline
DummyInt
_isnan
(...)
{
inline
DummyInt
_isnan
(...)
{
return
DummyInt
();
return
DummyInt
();
}
}
// A helper function to suppress bogus "conditional expression is constant"
// A helper function to suppress bogus "conditional expression is constant"
// warnings.
// warnings.
template
<
typename
T
>
template
<
typename
T
>
inline
T
check
(
T
value
)
{
inline
T
check
(
T
value
)
{
return
value
;
return
value
;
}
}
}
}
}
// namespace fmt
}
// namespace fmt
namespace
std
{
namespace
std
{
// Standard permits specialization of std::numeric_limits. This specialization
// Standard permits specialization of std::numeric_limits. This specialization
// is used to resolve ambiguity between isinf and std::isinf in glibc:
// is used to resolve ambiguity between isinf and std::isinf in glibc:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891
// and the same for isnan and signbit.
// and the same for isnan and signbit.
template
<>
template
<>
class
numeric_limits
<
fmt
::
internal
::
DummyInt
>
:
class
numeric_limits
<
fmt
::
internal
::
DummyInt
>
:
public
std
::
numeric_limits
<
int
>
{
public
std
::
numeric_limits
<
int
>
{
public
:
public
:
// Portable version of isinf.
// Portable version of isinf.
template
<
typename
T
>
template
<
typename
T
>
static
bool
isinfinity
(
T
x
)
{
static
bool
isinfinity
(
T
x
)
{
using
namespace
fmt
::
internal
;
using
namespace
fmt
::
internal
;
// The resolution "priority" is:
// The resolution "priority" is:
// isinf macro > std::isinf > ::isinf > fmt::internal::isinf
// isinf macro > std::isinf > ::isinf > fmt::internal::isinf
if
(
check
(
sizeof
(
isinf
(
x
))
==
sizeof
(
bool
)
||
if
(
check
(
sizeof
(
isinf
(
x
))
==
sizeof
(
bool
)
||
sizeof
(
isinf
(
x
))
==
sizeof
(
int
)))
{
sizeof
(
isinf
(
x
))
==
sizeof
(
int
)))
{
return
isinf
(
x
)
!=
0
;
return
isinf
(
x
)
!=
0
;
}
}
return
!
_finite
(
static_cast
<
double
>
(
x
));
return
!
_finite
(
static_cast
<
double
>
(
x
));
...
@@ -318,17 +337,20 @@ public:
...
@@ -318,17 +337,20 @@ public:
// Portable version of isnan.
// Portable version of isnan.
template
<
typename
T
>
template
<
typename
T
>
static
bool
isnotanumber
(
T
x
)
{
static
bool
isnotanumber
(
T
x
)
{
using
namespace
fmt
::
internal
;
using
namespace
fmt
::
internal
;
if
(
check
(
sizeof
(
isnan
(
x
))
==
sizeof
(
bool
)
||
if
(
check
(
sizeof
(
isnan
(
x
))
==
sizeof
(
bool
)
||
sizeof
(
isnan
(
x
))
==
sizeof
(
int
)))
{
sizeof
(
isnan
(
x
))
==
sizeof
(
int
)))
{
return
isnan
(
x
)
!=
0
;
return
isnan
(
x
)
!=
0
;
}
}
return
_isnan
(
static_cast
<
double
>
(
x
))
!=
0
;
return
_isnan
(
static_cast
<
double
>
(
x
))
!=
0
;
}
}
// Portable version of signbit.
// Portable version of signbit.
static
bool
isnegative
(
double
x
)
{
static
bool
isnegative
(
double
x
)
{
using
namespace
fmt
::
internal
;
using
namespace
fmt
::
internal
;
if
(
check
(
sizeof
(
signbit
(
x
))
==
sizeof
(
int
)))
if
(
check
(
sizeof
(
signbit
(
x
))
==
sizeof
(
int
)))
return
signbit
(
x
)
!=
0
;
return
signbit
(
x
)
!=
0
;
...
@@ -342,7 +364,8 @@ public:
...
@@ -342,7 +364,8 @@ public:
};
};
}
// namespace std
}
// namespace std
namespace
fmt
{
namespace
fmt
{
// Fix the warning about long long on older versions of GCC
// Fix the warning about long long on older versions of GCC
// that don't support the diagnostic pragma.
// that don't support the diagnostic pragma.
...
@@ -390,7 +413,8 @@ format(std::string("{}"), 42);
...
@@ -390,7 +413,8 @@ format(std::string("{}"), 42);
\endrst
\endrst
*/
*/
template
<
typename
Char
>
template
<
typename
Char
>
class
BasicStringRef
{
class
BasicStringRef
{
private
:
private
:
const
Char
*
data_
;
const
Char
*
data_
;
std
::
size_t
size_
;
std
::
size_t
size_
;
...
@@ -421,22 +445,26 @@ public:
...
@@ -421,22 +445,26 @@ public:
Converts a string reference to an ``std::string`` object.
Converts a string reference to an ``std::string`` object.
\endrst
\endrst
*/
*/
std
::
basic_string
<
Char
>
to_string
()
const
{
std
::
basic_string
<
Char
>
to_string
()
const
{
return
std
::
basic_string
<
Char
>
(
data_
,
size_
);
return
std
::
basic_string
<
Char
>
(
data_
,
size_
);
}
}
/** Returns the pointer to a C string. */
/** Returns the pointer to a C string. */
const
Char
*
data
()
const
{
const
Char
*
data
()
const
{
return
data_
;
return
data_
;
}
}
/** Returns the string size. */
/** Returns the string size. */
std
::
size_t
size
()
const
{
std
::
size_t
size
()
const
{
return
size_
;
return
size_
;
}
}
// Lexicographically compare this string reference to other.
// Lexicographically compare this string reference to other.
int
compare
(
BasicStringRef
other
)
const
{
int
compare
(
BasicStringRef
other
)
const
{
std
::
size_t
size
=
size_
<
other
.
size_
?
size_
:
other
.
size_
;
std
::
size_t
size
=
size_
<
other
.
size_
?
size_
:
other
.
size_
;
int
result
=
std
::
char_traits
<
Char
>::
compare
(
data_
,
other
.
data_
,
size
);
int
result
=
std
::
char_traits
<
Char
>::
compare
(
data_
,
other
.
data_
,
size
);
if
(
result
==
0
)
if
(
result
==
0
)
...
@@ -444,22 +472,28 @@ public:
...
@@ -444,22 +472,28 @@ public:
return
result
;
return
result
;
}
}
friend
bool
operator
==
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
friend
bool
operator
==
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
compare
(
rhs
)
==
0
;
return
lhs
.
compare
(
rhs
)
==
0
;
}
}
friend
bool
operator
!=
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
friend
bool
operator
!=
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
compare
(
rhs
)
!=
0
;
return
lhs
.
compare
(
rhs
)
!=
0
;
}
}
friend
bool
operator
<
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
friend
bool
operator
<
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
compare
(
rhs
)
<
0
;
return
lhs
.
compare
(
rhs
)
<
0
;
}
}
friend
bool
operator
<=
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
friend
bool
operator
<=
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
compare
(
rhs
)
<=
0
;
return
lhs
.
compare
(
rhs
)
<=
0
;
}
}
friend
bool
operator
>
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
friend
bool
operator
>
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
compare
(
rhs
)
>
0
;
return
lhs
.
compare
(
rhs
)
>
0
;
}
}
friend
bool
operator
>=
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
friend
bool
operator
>=
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
compare
(
rhs
)
>=
0
;
return
lhs
.
compare
(
rhs
)
>=
0
;
}
}
};
};
...
@@ -493,7 +527,8 @@ format(std::string("{}"), 42);
...
@@ -493,7 +527,8 @@ format(std::string("{}"), 42);
\endrst
\endrst
*/
*/
template
<
typename
Char
>
template
<
typename
Char
>
class
BasicCStringRef
{
class
BasicCStringRef
{
private
:
private
:
const
Char
*
data_
;
const
Char
*
data_
;
...
@@ -509,7 +544,8 @@ public:
...
@@ -509,7 +544,8 @@ public:
BasicCStringRef
(
const
std
::
basic_string
<
Char
>
&
s
)
:
data_
(
s
.
c_str
())
{}
BasicCStringRef
(
const
std
::
basic_string
<
Char
>
&
s
)
:
data_
(
s
.
c_str
())
{}
/** Returns the pointer to a C string. */
/** Returns the pointer to a C string. */
const
Char
*
c_str
()
const
{
const
Char
*
c_str
()
const
{
return
data_
;
return
data_
;
}
}
};
};
...
@@ -520,13 +556,15 @@ typedef BasicCStringRef<wchar_t> WCStringRef;
...
@@ -520,13 +556,15 @@ typedef BasicCStringRef<wchar_t> WCStringRef;
/**
/**
A formatting error such as invalid format string.
A formatting error such as invalid format string.
*/
*/
class
FormatError
:
public
std
::
runtime_error
{
class
FormatError
:
public
std
::
runtime_error
{
public
:
public
:
explicit
FormatError
(
CStringRef
message
)
explicit
FormatError
(
CStringRef
message
)
:
std
::
runtime_error
(
message
.
c_str
())
{}
:
std
::
runtime_error
(
message
.
c_str
())
{}
};
};
namespace
internal
{
namespace
internal
{
// The number of characters to store in the MemoryBuffer object itself
// The number of characters to store in the MemoryBuffer object itself
// to avoid dynamic memory allocation.
// to avoid dynamic memory allocation.
enum
{
INLINE_BUFFER_SIZE
=
500
};
enum
{
INLINE_BUFFER_SIZE
=
500
};
...
@@ -534,12 +572,14 @@ enum { INLINE_BUFFER_SIZE = 500 };
...
@@ -534,12 +572,14 @@ enum { INLINE_BUFFER_SIZE = 500 };
#if FMT_SECURE_SCL
#if FMT_SECURE_SCL
// Use checked iterator to avoid warnings on MSVC.
// Use checked iterator to avoid warnings on MSVC.
template
<
typename
T
>
template
<
typename
T
>
inline
stdext
::
checked_array_iterator
<
T
*>
make_ptr
(
T
*
ptr
,
std
::
size_t
size
)
{
inline
stdext
::
checked_array_iterator
<
T
*>
make_ptr
(
T
*
ptr
,
std
::
size_t
size
)
{
return
stdext
::
checked_array_iterator
<
T
*>
(
ptr
,
size
);
return
stdext
::
checked_array_iterator
<
T
*>
(
ptr
,
size
);
}
}
#else
#else
template
<
typename
T
>
template
<
typename
T
>
inline
T
*
make_ptr
(
T
*
ptr
,
std
::
size_t
)
{
inline
T
*
make_ptr
(
T
*
ptr
,
std
::
size_t
)
{
return
ptr
;
return
ptr
;
}
}
#endif
#endif
...
@@ -551,7 +591,8 @@ A buffer supporting a subset of ``std::vector``'s operations.
...
@@ -551,7 +591,8 @@ A buffer supporting a subset of ``std::vector``'s operations.
\endrst
\endrst
*/
*/
template
<
typename
T
>
template
<
typename
T
>
class
Buffer
{
class
Buffer
{
private
:
private
:
FMT_DISALLOW_COPY_AND_ASSIGN
(
Buffer
);
FMT_DISALLOW_COPY_AND_ASSIGN
(
Buffer
);
...
@@ -575,19 +616,22 @@ public:
...
@@ -575,19 +616,22 @@ public:
virtual
~
Buffer
()
{}
virtual
~
Buffer
()
{}
/** Returns the size of this buffer. */
/** Returns the size of this buffer. */
std
::
size_t
size
()
const
{
std
::
size_t
size
()
const
{
return
size_
;
return
size_
;
}
}
/** Returns the capacity of this buffer. */
/** Returns the capacity of this buffer. */
std
::
size_t
capacity
()
const
{
std
::
size_t
capacity
()
const
{
return
capacity_
;
return
capacity_
;
}
}
/**
/**
Resizes the buffer. If T is a POD type new elements may not be initialized.
Resizes the buffer. If T is a POD type new elements may not be initialized.
*/
*/
void
resize
(
std
::
size_t
new_size
)
{
void
resize
(
std
::
size_t
new_size
)
{
if
(
new_size
>
capacity_
)
if
(
new_size
>
capacity_
)
grow
(
new_size
);
grow
(
new_size
);
size_
=
new_size
;
size_
=
new_size
;
...
@@ -598,14 +642,16 @@ public:
...
@@ -598,14 +642,16 @@ public:
Reserves space to store at least *capacity* elements.
Reserves space to store at least *capacity* elements.
\endrst
\endrst
*/
*/
void
reserve
(
std
::
size_t
capacity
)
{
void
reserve
(
std
::
size_t
capacity
)
{
if
(
capacity
>
capacity_
)
if
(
capacity
>
capacity_
)
grow
(
capacity
);
grow
(
capacity
);
}
}
void
clear
()
FMT_NOEXCEPT
{
size_
=
0
;
}
void
clear
()
FMT_NOEXCEPT
{
size_
=
0
;
}
void
push_back
(
const
T
&
value
)
{
void
push_back
(
const
T
&
value
)
{
if
(
size_
==
capacity_
)
if
(
size_
==
capacity_
)
grow
(
size_
+
1
);
grow
(
size_
+
1
);
ptr_
[
size_
++
]
=
value
;
ptr_
[
size_
++
]
=
value
;
...
@@ -615,17 +661,20 @@ public:
...
@@ -615,17 +661,20 @@ public:
template
<
typename
U
>
template
<
typename
U
>
void
append
(
const
U
*
begin
,
const
U
*
end
);
void
append
(
const
U
*
begin
,
const
U
*
end
);
T
&
operator
[](
std
::
size_t
index
)
{
T
&
operator
[](
std
::
size_t
index
)
{
return
ptr_
[
index
];
return
ptr_
[
index
];
}
}
const
T
&
operator
[](
std
::
size_t
index
)
const
{
const
T
&
operator
[](
std
::
size_t
index
)
const
{
return
ptr_
[
index
];
return
ptr_
[
index
];
}
}
};
};
template
<
typename
T
>
template
<
typename
T
>
template
<
typename
U
>
template
<
typename
U
>
void
Buffer
<
T
>::
append
(
const
U
*
begin
,
const
U
*
end
)
{
void
Buffer
<
T
>::
append
(
const
U
*
begin
,
const
U
*
end
)
{
assert
(
begin
<=
end
);
assert
(
begin
<=
end
);
std
::
size_t
new_size
=
size_
+
(
end
-
begin
);
std
::
size_t
new_size
=
size_
+
(
end
-
begin
);
if
(
new_size
>
capacity_
)
if
(
new_size
>
capacity_
)
...
@@ -635,17 +684,20 @@ void Buffer<T>::append(const U *begin, const U *end) {
...
@@ -635,17 +684,20 @@ void Buffer<T>::append(const U *begin, const U *end) {
size_
=
new_size
;
size_
=
new_size
;
}
}
namespace
internal
{
namespace
internal
{
// A memory buffer for POD types with the first SIZE elements stored in
// A memory buffer for POD types with the first SIZE elements stored in
// the object itself.
// the object itself.
template
<
typename
T
,
std
::
size_t
SIZE
,
typename
Allocator
=
std
::
allocator
<
T
>
>
template
<
typename
T
,
std
::
size_t
SIZE
,
typename
Allocator
=
std
::
allocator
<
T
>
>
class
MemoryBuffer
:
private
Allocator
,
public
Buffer
<
T
>
{
class
MemoryBuffer
:
private
Allocator
,
public
Buffer
<
T
>
{
private
:
private
:
T
data_
[
SIZE
];
T
data_
[
SIZE
];
// Deallocate memory allocated by the buffer.
// Deallocate memory allocated by the buffer.
void
deallocate
()
{
void
deallocate
()
{
if
(
this
->
ptr_
!=
data_
)
Allocator
::
deallocate
(
this
->
ptr_
,
this
->
capacity_
);
if
(
this
->
ptr_
!=
data_
)
Allocator
::
deallocate
(
this
->
ptr_
,
this
->
capacity_
);
}
}
...
@@ -655,24 +707,28 @@ protected:
...
@@ -655,24 +707,28 @@ protected:
public
:
public
:
explicit
MemoryBuffer
(
const
Allocator
&
alloc
=
Allocator
())
explicit
MemoryBuffer
(
const
Allocator
&
alloc
=
Allocator
())
:
Allocator
(
alloc
),
Buffer
<
T
>
(
data_
,
SIZE
)
{}
:
Allocator
(
alloc
),
Buffer
<
T
>
(
data_
,
SIZE
)
{}
~
MemoryBuffer
()
{
~
MemoryBuffer
()
{
deallocate
();
deallocate
();
}
}
#if FMT_USE_RVALUE_REFERENCES
#if FMT_USE_RVALUE_REFERENCES
private
:
private
:
// Move data from other to this buffer.
// Move data from other to this buffer.
void
move
(
MemoryBuffer
&
other
)
{
void
move
(
MemoryBuffer
&
other
)
{
Allocator
&
this_alloc
=
*
this
,
&
other_alloc
=
other
;
Allocator
&
this_alloc
=
*
this
,
&
other_alloc
=
other
;
this_alloc
=
std
::
move
(
other_alloc
);
this_alloc
=
std
::
move
(
other_alloc
);
this
->
size_
=
other
.
size_
;
this
->
size_
=
other
.
size_
;
this
->
capacity_
=
other
.
capacity_
;
this
->
capacity_
=
other
.
capacity_
;
if
(
other
.
ptr_
==
other
.
data_
)
{
if
(
other
.
ptr_
==
other
.
data_
)
{
this
->
ptr_
=
data_
;
this
->
ptr_
=
data_
;
std
::
uninitialized_copy
(
other
.
data_
,
other
.
data_
+
this
->
size_
,
std
::
uninitialized_copy
(
other
.
data_
,
other
.
data_
+
this
->
size_
,
make_ptr
(
data_
,
this
->
capacity_
));
make_ptr
(
data_
,
this
->
capacity_
));
}
}
else
{
else
{
this
->
ptr_
=
other
.
ptr_
;
this
->
ptr_
=
other
.
ptr_
;
// Set pointer to the inline array so that delete is not called
// Set pointer to the inline array so that delete is not called
// when deallocating.
// when deallocating.
...
@@ -681,11 +737,13 @@ private:
...
@@ -681,11 +737,13 @@ private:
}
}
public
:
public
:
MemoryBuffer
(
MemoryBuffer
&&
other
)
{
MemoryBuffer
(
MemoryBuffer
&&
other
)
{
move
(
other
);
move
(
other
);
}
}
MemoryBuffer
&
operator
=
(
MemoryBuffer
&&
other
)
{
MemoryBuffer
&
operator
=
(
MemoryBuffer
&&
other
)
{
assert
(
this
!=
&
other
);
assert
(
this
!=
&
other
);
deallocate
();
deallocate
();
move
(
other
);
move
(
other
);
...
@@ -694,13 +752,15 @@ public:
...
@@ -694,13 +752,15 @@ public:
#endif
#endif
// Returns a copy of the allocator associated with this buffer.
// Returns a copy of the allocator associated with this buffer.
Allocator
get_allocator
()
const
{
Allocator
get_allocator
()
const
{
return
*
this
;
return
*
this
;
}
}
};
};
template
<
typename
T
,
std
::
size_t
SIZE
,
typename
Allocator
>
template
<
typename
T
,
std
::
size_t
SIZE
,
typename
Allocator
>
void
MemoryBuffer
<
T
,
SIZE
,
Allocator
>::
grow
(
std
::
size_t
size
)
{
void
MemoryBuffer
<
T
,
SIZE
,
Allocator
>::
grow
(
std
::
size_t
size
)
{
std
::
size_t
new_capacity
=
this
->
capacity_
+
this
->
capacity_
/
2
;
std
::
size_t
new_capacity
=
this
->
capacity_
+
this
->
capacity_
/
2
;
if
(
size
>
new_capacity
)
if
(
size
>
new_capacity
)
new_capacity
=
size
;
new_capacity
=
size
;
...
@@ -721,7 +781,8 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
...
@@ -721,7 +781,8 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
// A fixed-size buffer.
// A fixed-size buffer.
template
<
typename
Char
>
template
<
typename
Char
>
class
FixedBuffer
:
public
fmt
::
Buffer
<
Char
>
{
class
FixedBuffer
:
public
fmt
::
Buffer
<
Char
>
{
public
:
public
:
FixedBuffer
(
Char
*
array
,
std
::
size_t
size
)
:
fmt
::
Buffer
<
Char
>
(
array
,
size
)
{}
FixedBuffer
(
Char
*
array
,
std
::
size_t
size
)
:
fmt
::
Buffer
<
Char
>
(
array
,
size
)
{}
...
@@ -730,14 +791,16 @@ protected:
...
@@ -730,14 +791,16 @@ protected:
};
};
template
<
typename
Char
>
template
<
typename
Char
>
class
BasicCharTraits
{
class
BasicCharTraits
{
public
:
public
:
#if FMT_SECURE_SCL
#if FMT_SECURE_SCL
typedef
stdext
::
checked_array_iterator
<
Char
*>
CharPtr
;
typedef
stdext
::
checked_array_iterator
<
Char
*>
CharPtr
;
#else
#else
typedef
Char
*
CharPtr
;
typedef
Char
*
CharPtr
;
#endif
#endif
static
Char
cast
(
int
value
)
{
static
Char
cast
(
int
value
)
{
return
static_cast
<
Char
>
(
value
);
return
static_cast
<
Char
>
(
value
);
}
}
};
};
...
@@ -746,13 +809,15 @@ template <typename Char>
...
@@ -746,13 +809,15 @@ template <typename Char>
class
CharTraits
;
class
CharTraits
;
template
<>
template
<>
class
CharTraits
<
char
>
:
public
BasicCharTraits
<
char
>
{
class
CharTraits
<
char
>
:
public
BasicCharTraits
<
char
>
{
private
:
private
:
// Conversion from wchar_t to char is not allowed.
// Conversion from wchar_t to char is not allowed.
static
char
convert
(
wchar_t
);
static
char
convert
(
wchar_t
);
public
:
public
:
static
char
convert
(
char
value
)
{
static
char
convert
(
char
value
)
{
return
value
;
return
value
;
}
}
...
@@ -763,12 +828,15 @@ public:
...
@@ -763,12 +828,15 @@ public:
};
};
template
<>
template
<>
class
CharTraits
<
wchar_t
>
:
public
BasicCharTraits
<
wchar_t
>
{
class
CharTraits
<
wchar_t
>
:
public
BasicCharTraits
<
wchar_t
>
{
public
:
public
:
static
wchar_t
convert
(
char
value
)
{
static
wchar_t
convert
(
char
value
)
{
return
value
;
return
value
;
}
}
static
wchar_t
convert
(
wchar_t
value
)
{
static
wchar_t
convert
(
wchar_t
value
)
{
return
value
;
return
value
;
}
}
...
@@ -779,17 +847,21 @@ public:
...
@@ -779,17 +847,21 @@ public:
// Checks if a number is negative - used to avoid warnings.
// Checks if a number is negative - used to avoid warnings.
template
<
bool
IsSigned
>
template
<
bool
IsSigned
>
struct
SignChecker
{
struct
SignChecker
{
template
<
typename
T
>
template
<
typename
T
>
static
bool
is_negative
(
T
value
)
{
static
bool
is_negative
(
T
value
)
{
return
value
<
0
;
return
value
<
0
;
}
}
};
};
template
<>
template
<>
struct
SignChecker
<
false
>
{
struct
SignChecker
<
false
>
{
template
<
typename
T
>
template
<
typename
T
>
static
bool
is_negative
(
T
)
{
static
bool
is_negative
(
T
)
{
return
false
;
return
false
;
}
}
};
};
...
@@ -797,23 +869,27 @@ struct SignChecker<false> {
...
@@ -797,23 +869,27 @@ struct SignChecker<false> {
// Returns true if value is negative, false otherwise.
// Returns true if value is negative, false otherwise.
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
template
<
typename
T
>
template
<
typename
T
>
inline
bool
is_negative
(
T
value
)
{
inline
bool
is_negative
(
T
value
)
{
return
SignChecker
<
std
::
numeric_limits
<
T
>::
is_signed
>::
is_negative
(
value
);
return
SignChecker
<
std
::
numeric_limits
<
T
>::
is_signed
>::
is_negative
(
value
);
}
}
// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.
// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.
template
<
bool
FitsIn32Bits
>
template
<
bool
FitsIn32Bits
>
struct
TypeSelector
{
struct
TypeSelector
{
typedef
uint32_t
Type
;
typedef
uint32_t
Type
;
};
};
template
<>
template
<>
struct
TypeSelector
<
false
>
{
struct
TypeSelector
<
false
>
{
typedef
uint64_t
Type
;
typedef
uint64_t
Type
;
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
IntTraits
{
struct
IntTraits
{
// Smallest of uint32_t and uint64_t that is large enough to represent
// Smallest of uint32_t and uint64_t that is large enough to represent
// all values of T.
// all values of T.
typedef
typename
typedef
typename
...
@@ -822,7 +898,8 @@ struct IntTraits {
...
@@ -822,7 +898,8 @@ struct IntTraits {
// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
template
<
typename
T
>
template
<
typename
T
>
struct
MakeUnsigned
{
struct
MakeUnsigned
{
typedef
T
Type
;
typedef
T
Type
;
};
};
...
@@ -842,7 +919,8 @@ FMT_API void report_unknown_type(char code, const char *type);
...
@@ -842,7 +919,8 @@ FMT_API void report_unknown_type(char code, const char *type);
// Static data is placed in this class template to allow header-only
// Static data is placed in this class template to allow header-only
// configuration.
// configuration.
template
<
typename
T
=
void
>
template
<
typename
T
=
void
>
struct
FMT_API
BasicData
{
struct
FMT_API
BasicData
{
static
const
uint32_t
POWERS_OF_10_32
[];
static
const
uint32_t
POWERS_OF_10_32
[];
static
const
uint64_t
POWERS_OF_10_64
[];
static
const
uint64_t
POWERS_OF_10_64
[];
static
const
char
DIGITS
[];
static
const
char
DIGITS
[];
...
@@ -861,7 +939,8 @@ typedef BasicData<> Data;
...
@@ -861,7 +939,8 @@ typedef BasicData<> Data;
#ifdef FMT_BUILTIN_CLZLL
#ifdef FMT_BUILTIN_CLZLL
// Returns the number of decimal digits in n. Leading zeros are not counted
// Returns the number of decimal digits in n. Leading zeros are not counted
// except for n == 0 in which case count_digits returns 1.
// except for n == 0 in which case count_digits returns 1.
inline
unsigned
count_digits
(
uint64_t
n
)
{
inline
unsigned
count_digits
(
uint64_t
n
)
{
// Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
// Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
// and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
// and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
unsigned
t
=
(
64
-
FMT_BUILTIN_CLZLL
(
n
|
1
))
*
1233
>>
12
;
unsigned
t
=
(
64
-
FMT_BUILTIN_CLZLL
(
n
|
1
))
*
1233
>>
12
;
...
@@ -869,9 +948,11 @@ inline unsigned count_digits(uint64_t n) {
...
@@ -869,9 +948,11 @@ inline unsigned count_digits(uint64_t n) {
}
}
#else
#else
// Fallback version of count_digits used when __builtin_clz is not available.
// Fallback version of count_digits used when __builtin_clz is not available.
inline
unsigned
count_digits
(
uint64_t
n
)
{
inline
unsigned
count_digits
(
uint64_t
n
)
{
unsigned
count
=
1
;
unsigned
count
=
1
;
for
(;;)
{
for
(;;)
{
// Integer division is slow so do it for a group of four digits instead
// Integer division is slow so do it for a group of four digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
// "Three Optimization Tips for C++". See speed-test for a comparison.
...
@@ -887,7 +968,8 @@ inline unsigned count_digits(uint64_t n) {
...
@@ -887,7 +968,8 @@ inline unsigned count_digits(uint64_t n) {
#ifdef FMT_BUILTIN_CLZ
#ifdef FMT_BUILTIN_CLZ
// Optional version of count_digits for better performance on 32-bit platforms.
// Optional version of count_digits for better performance on 32-bit platforms.
inline
unsigned
count_digits
(
uint32_t
n
)
{
inline
unsigned
count_digits
(
uint32_t
n
)
{
uint32_t
t
=
(
32
-
FMT_BUILTIN_CLZ
(
n
|
1
))
*
1233
>>
12
;
uint32_t
t
=
(
32
-
FMT_BUILTIN_CLZ
(
n
|
1
))
*
1233
>>
12
;
return
t
-
(
n
<
Data
::
POWERS_OF_10_32
[
t
])
+
1
;
return
t
-
(
n
<
Data
::
POWERS_OF_10_32
[
t
])
+
1
;
}
}
...
@@ -895,9 +977,11 @@ inline unsigned count_digits(uint32_t n) {
...
@@ -895,9 +977,11 @@ inline unsigned count_digits(uint32_t n) {
// Formats a decimal unsigned integer value writing into buffer.
// Formats a decimal unsigned integer value writing into buffer.
template
<
typename
UInt
,
typename
Char
>
template
<
typename
UInt
,
typename
Char
>
inline
void
format_decimal
(
Char
*
buffer
,
UInt
value
,
unsigned
num_digits
)
{
inline
void
format_decimal
(
Char
*
buffer
,
UInt
value
,
unsigned
num_digits
)
{
buffer
+=
num_digits
;
buffer
+=
num_digits
;
while
(
value
>=
100
)
{
while
(
value
>=
100
)
{
// Integer division is slow so do it for a group of two digits instead
// Integer division is slow so do it for a group of two digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
// "Three Optimization Tips for C++". See speed-test for a comparison.
...
@@ -906,7 +990,8 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
...
@@ -906,7 +990,8 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
*--
buffer
=
Data
::
DIGITS
[
index
+
1
];
*--
buffer
=
Data
::
DIGITS
[
index
+
1
];
*--
buffer
=
Data
::
DIGITS
[
index
];
*--
buffer
=
Data
::
DIGITS
[
index
];
}
}
if
(
value
<
10
)
{
if
(
value
<
10
)
{
*--
buffer
=
static_cast
<
char
>
(
'0'
+
value
);
*--
buffer
=
static_cast
<
char
>
(
'0'
+
value
);
return
;
return
;
}
}
...
@@ -926,45 +1011,55 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
...
@@ -926,45 +1011,55 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
#if FMT_USE_WINDOWS_H
#if FMT_USE_WINDOWS_H
// A converter from UTF-8 to UTF-16.
// A converter from UTF-8 to UTF-16.
// It is only provided for Windows since other systems support UTF-8 natively.
// It is only provided for Windows since other systems support UTF-8 natively.
class
UTF8ToUTF16
{
class
UTF8ToUTF16
{
private
:
private
:
MemoryBuffer
<
wchar_t
,
INLINE_BUFFER_SIZE
>
buffer_
;
MemoryBuffer
<
wchar_t
,
INLINE_BUFFER_SIZE
>
buffer_
;
public
:
public
:
FMT_API
explicit
UTF8ToUTF16
(
StringRef
s
);
FMT_API
explicit
UTF8ToUTF16
(
StringRef
s
);
operator
WStringRef
()
const
{
operator
WStringRef
()
const
{
return
WStringRef
(
&
buffer_
[
0
],
size
());
return
WStringRef
(
&
buffer_
[
0
],
size
());
}
}
size_t
size
()
const
{
size_t
size
()
const
{
return
buffer_
.
size
()
-
1
;
return
buffer_
.
size
()
-
1
;
}
}
const
wchar_t
*
c_str
()
const
{
const
wchar_t
*
c_str
()
const
{
return
&
buffer_
[
0
];
return
&
buffer_
[
0
];
}
}
std
::
wstring
str
()
const
{
std
::
wstring
str
()
const
{
return
std
::
wstring
(
&
buffer_
[
0
],
size
());
return
std
::
wstring
(
&
buffer_
[
0
],
size
());
}
}
};
};
// A converter from UTF-16 to UTF-8.
// A converter from UTF-16 to UTF-8.
// It is only provided for Windows since other systems support UTF-8 natively.
// It is only provided for Windows since other systems support UTF-8 natively.
class
UTF16ToUTF8
{
class
UTF16ToUTF8
{
private
:
private
:
MemoryBuffer
<
char
,
INLINE_BUFFER_SIZE
>
buffer_
;
MemoryBuffer
<
char
,
INLINE_BUFFER_SIZE
>
buffer_
;
public
:
public
:
UTF16ToUTF8
()
{}
UTF16ToUTF8
()
{}
FMT_API
explicit
UTF16ToUTF8
(
WStringRef
s
);
FMT_API
explicit
UTF16ToUTF8
(
WStringRef
s
);
operator
StringRef
()
const
{
operator
StringRef
()
const
{
return
StringRef
(
&
buffer_
[
0
],
size
());
return
StringRef
(
&
buffer_
[
0
],
size
());
}
}
size_t
size
()
const
{
size_t
size
()
const
{
return
buffer_
.
size
()
-
1
;
return
buffer_
.
size
()
-
1
;
}
}
const
char
*
c_str
()
const
{
const
char
*
c_str
()
const
{
return
&
buffer_
[
0
];
return
&
buffer_
[
0
];
}
}
std
::
string
str
()
const
{
std
::
string
str
()
const
{
return
std
::
string
(
&
buffer_
[
0
],
size
());
return
std
::
string
(
&
buffer_
[
0
],
size
());
}
}
...
@@ -982,9 +1077,11 @@ FMT_API void format_system_error(fmt::Writer &out, int error_code,
...
@@ -982,9 +1077,11 @@ FMT_API void format_system_error(fmt::Writer &out, int error_code,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
;
fmt
::
StringRef
message
)
FMT_NOEXCEPT
;
// A formatting argument value.
// A formatting argument value.
struct
Value
{
struct
Value
{
template
<
typename
Char
>
template
<
typename
Char
>
struct
StringValue
{
struct
StringValue
{
const
Char
*
value
;
const
Char
*
value
;
std
::
size_t
size
;
std
::
size_t
size
;
};
};
...
@@ -992,12 +1089,14 @@ struct Value {
...
@@ -992,12 +1089,14 @@ struct Value {
typedef
void
(
*
FormatFunc
)(
typedef
void
(
*
FormatFunc
)(
void
*
formatter
,
const
void
*
arg
,
void
*
format_str_ptr
);
void
*
formatter
,
const
void
*
arg
,
void
*
format_str_ptr
);
struct
CustomValue
{
struct
CustomValue
{
const
void
*
value
;
const
void
*
value
;
FormatFunc
format
;
FormatFunc
format
;
};
};
union
{
union
{
int
int_value
;
int
int_value
;
unsigned
uint_value
;
unsigned
uint_value
;
LongLong
long_long_value
;
LongLong
long_long_value
;
...
@@ -1012,7 +1111,8 @@ struct Value {
...
@@ -1012,7 +1111,8 @@ struct Value {
CustomValue
custom
;
CustomValue
custom
;
};
};
enum
Type
{
enum
Type
{
NONE
,
NAMED_ARG
,
NONE
,
NAMED_ARG
,
// Integer types should go first,
// Integer types should go first,
INT
,
UINT
,
LONG_LONG
,
ULONG_LONG
,
BOOL
,
CHAR
,
LAST_INTEGER_TYPE
=
CHAR
,
INT
,
UINT
,
LONG_LONG
,
ULONG_LONG
,
BOOL
,
CHAR
,
LAST_INTEGER_TYPE
=
CHAR
,
...
@@ -1024,7 +1124,8 @@ struct Value {
...
@@ -1024,7 +1124,8 @@ struct Value {
// A formatting argument. It is a POD type to allow storage in
// A formatting argument. It is a POD type to allow storage in
// internal::MemoryBuffer.
// internal::MemoryBuffer.
struct
Arg
:
Value
{
struct
Arg
:
Value
{
Type
type
;
Type
type
;
};
};
...
@@ -1037,13 +1138,15 @@ struct Null {};
...
@@ -1037,13 +1138,15 @@ struct Null {};
// A helper class template to enable or disable overloads taking wide
// A helper class template to enable or disable overloads taking wide
// characters and strings in MakeValue.
// characters and strings in MakeValue.
template
<
typename
T
,
typename
Char
>
template
<
typename
T
,
typename
Char
>
struct
WCharHelper
{
struct
WCharHelper
{
typedef
Null
<
T
>
Supported
;
typedef
Null
<
T
>
Supported
;
typedef
T
Unsupported
;
typedef
T
Unsupported
;
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
WCharHelper
<
T
,
wchar_t
>
{
struct
WCharHelper
<
T
,
wchar_t
>
{
typedef
T
Supported
;
typedef
T
Supported
;
typedef
Null
<
T
>
Unsupported
;
typedef
Null
<
T
>
Unsupported
;
};
};
...
@@ -1059,7 +1162,8 @@ No &convert(...);
...
@@ -1059,7 +1162,8 @@ No &convert(...);
template
<
typename
T
>
template
<
typename
T
>
T
&
get
();
T
&
get
();
struct
DummyStream
:
std
::
ostream
{
struct
DummyStream
:
std
::
ostream
{
DummyStream
();
// Suppress a bogus warning in MSVC.
DummyStream
();
// Suppress a bogus warning in MSVC.
// Hide all operator<< overloads from std::ostream.
// Hide all operator<< overloads from std::ostream.
void
operator
<<
(
Null
<>
);
void
operator
<<
(
Null
<>
);
...
@@ -1068,33 +1172,40 @@ struct DummyStream : std::ostream {
...
@@ -1068,33 +1172,40 @@ struct DummyStream : std::ostream {
No
&
operator
<<
(
std
::
ostream
&
,
int
);
No
&
operator
<<
(
std
::
ostream
&
,
int
);
template
<
typename
T
,
bool
ENABLE_CONVERSION
>
template
<
typename
T
,
bool
ENABLE_CONVERSION
>
struct
ConvertToIntImpl
{
struct
ConvertToIntImpl
{
enum
{
value
=
false
};
enum
{
value
=
false
};
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
ConvertToIntImpl
<
T
,
true
>
{
struct
ConvertToIntImpl
<
T
,
true
>
{
// Convert to int only if T doesn't have an overloaded operator<<.
// Convert to int only if T doesn't have an overloaded operator<<.
enum
{
enum
{
value
=
sizeof
(
convert
(
get
<
DummyStream
>
()
<<
get
<
T
>
()))
==
sizeof
(
No
)
value
=
sizeof
(
convert
(
get
<
DummyStream
>
()
<<
get
<
T
>
()))
==
sizeof
(
No
)
};
};
};
};
template
<
typename
T
,
bool
ENABLE_CONVERSION
>
template
<
typename
T
,
bool
ENABLE_CONVERSION
>
struct
ConvertToIntImpl2
{
struct
ConvertToIntImpl2
{
enum
{
value
=
false
};
enum
{
value
=
false
};
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
ConvertToIntImpl2
<
T
,
true
>
{
struct
ConvertToIntImpl2
<
T
,
true
>
enum
{
{
enum
{
// Don't convert numeric types.
// Don't convert numeric types.
value
=
ConvertToIntImpl
<
T
,
!
std
::
numeric_limits
<
T
>::
is_specialized
>::
value
value
=
ConvertToIntImpl
<
T
,
!
std
::
numeric_limits
<
T
>::
is_specialized
>::
value
};
};
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
ConvertToInt
{
struct
ConvertToInt
{
enum
{
enable_conversion
=
sizeof
(
convert
(
get
<
T
>
()))
==
sizeof
(
Yes
)
};
enum
{
enable_conversion
=
sizeof
(
convert
(
get
<
T
>
()))
==
sizeof
(
Yes
)
};
enum
{
value
=
ConvertToIntImpl2
<
T
,
enable_conversion
>::
value
};
enum
{
value
=
ConvertToIntImpl2
<
T
,
enable_conversion
>::
value
};
};
};
...
@@ -1112,34 +1223,40 @@ template<bool B, class T = void>
...
@@ -1112,34 +1223,40 @@ template<bool B, class T = void>
struct
EnableIf
{};
struct
EnableIf
{};
template
<
class
T
>
template
<
class
T
>
struct
EnableIf
<
true
,
T
>
{
struct
EnableIf
<
true
,
T
>
{
typedef
T
type
;
typedef
T
type
;
};
};
template
<
bool
B
,
class
T
,
class
F
>
template
<
bool
B
,
class
T
,
class
F
>
struct
Conditional
{
struct
Conditional
{
typedef
T
type
;
typedef
T
type
;
};
};
template
<
class
T
,
class
F
>
template
<
class
T
,
class
F
>
struct
Conditional
<
false
,
T
,
F
>
{
struct
Conditional
<
false
,
T
,
F
>
{
typedef
F
type
;
typedef
F
type
;
};
};
// For bcc32 which doesn't understand ! in template arguments.
// For bcc32 which doesn't understand ! in template arguments.
template
<
bool
>
template
<
bool
>
struct
Not
{
struct
Not
{
enum
{
value
=
0
};
enum
{
value
=
0
};
};
};
template
<>
template
<>
struct
Not
<
false
>
{
struct
Not
<
false
>
{
enum
{
value
=
1
};
enum
{
value
=
1
};
};
};
// Makes an Arg object from any type.
// Makes an Arg object from any type.
template
<
typename
Formatter
>
template
<
typename
Formatter
>
class
MakeValue
:
public
Arg
{
class
MakeValue
:
public
Arg
{
public
:
public
:
typedef
typename
Formatter
::
Char
Char
;
typedef
typename
Formatter
::
Char
Char
;
...
@@ -1166,12 +1283,14 @@ private:
...
@@ -1166,12 +1283,14 @@ private:
MakeValue
(
typename
WCharHelper
<
const
std
::
wstring
&
,
Char
>::
Unsupported
);
MakeValue
(
typename
WCharHelper
<
const
std
::
wstring
&
,
Char
>::
Unsupported
);
MakeValue
(
typename
WCharHelper
<
WStringRef
,
Char
>::
Unsupported
);
MakeValue
(
typename
WCharHelper
<
WStringRef
,
Char
>::
Unsupported
);
void
set_string
(
StringRef
str
)
{
void
set_string
(
StringRef
str
)
{
string
.
value
=
str
.
data
();
string
.
value
=
str
.
data
();
string
.
size
=
str
.
size
();
string
.
size
=
str
.
size
();
}
}
void
set_string
(
WStringRef
str
)
{
void
set_string
(
WStringRef
str
)
{
wstring
.
value
=
str
.
data
();
wstring
.
value
=
str
.
data
();
wstring
.
size
=
str
.
size
();
wstring
.
size
=
str
.
size
();
}
}
...
@@ -1179,7 +1298,8 @@ private:
...
@@ -1179,7 +1298,8 @@ private:
// Formats an argument of a custom type, such as a user-defined class.
// Formats an argument of a custom type, such as a user-defined class.
template
<
typename
T
>
template
<
typename
T
>
static
void
format_custom_arg
(
static
void
format_custom_arg
(
void
*
formatter
,
const
void
*
arg
,
void
*
format_str_ptr
)
{
void
*
formatter
,
const
void
*
arg
,
void
*
format_str_ptr
)
{
format
(
*
static_cast
<
Formatter
*>
(
formatter
),
format
(
*
static_cast
<
Formatter
*>
(
formatter
),
*
static_cast
<
const
Char
**>
(
format_str_ptr
),
*
static_cast
<
const
Char
**>
(
format_str_ptr
),
*
static_cast
<
const
T
*>
(
arg
));
*
static_cast
<
const
T
*>
(
arg
));
...
@@ -1201,7 +1321,8 @@ public:
...
@@ -1201,7 +1321,8 @@ public:
FMT_MAKE_VALUE
(
int
,
int_value
,
INT
)
FMT_MAKE_VALUE
(
int
,
int_value
,
INT
)
FMT_MAKE_VALUE
(
unsigned
,
uint_value
,
UINT
)
FMT_MAKE_VALUE
(
unsigned
,
uint_value
,
UINT
)
MakeValue
(
long
value
)
{
MakeValue
(
long
value
)
{
// To minimize the number of types we need to deal with, long is
// To minimize the number of types we need to deal with, long is
// translated either to int or to long long depending on its size.
// translated either to int or to long long depending on its size.
if
(
check
(
sizeof
(
long
)
==
sizeof
(
int
)))
if
(
check
(
sizeof
(
long
)
==
sizeof
(
int
)))
...
@@ -1209,17 +1330,20 @@ public:
...
@@ -1209,17 +1330,20 @@ public:
else
else
long_long_value
=
value
;
long_long_value
=
value
;
}
}
static
uint64_t
type
(
long
)
{
static
uint64_t
type
(
long
)
{
return
sizeof
(
long
)
==
sizeof
(
int
)
?
Arg
::
INT
:
Arg
::
LONG_LONG
;
return
sizeof
(
long
)
==
sizeof
(
int
)
?
Arg
::
INT
:
Arg
::
LONG_LONG
;
}
}
MakeValue
(
unsigned
long
value
)
{
MakeValue
(
unsigned
long
value
)
{
if
(
check
(
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
)))
if
(
check
(
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
)))
uint_value
=
static_cast
<
unsigned
>
(
value
);
uint_value
=
static_cast
<
unsigned
>
(
value
);
else
else
ulong_long_value
=
value
;
ulong_long_value
=
value
;
}
}
static
uint64_t
type
(
unsigned
long
)
{
static
uint64_t
type
(
unsigned
long
)
{
return
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
)
?
return
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
)
?
Arg
::
UINT
:
Arg
::
ULONG_LONG
;
Arg
::
UINT
:
Arg
::
ULONG_LONG
;
}
}
...
@@ -1234,10 +1358,12 @@ public:
...
@@ -1234,10 +1358,12 @@ public:
FMT_MAKE_VALUE
(
char
,
int_value
,
CHAR
)
FMT_MAKE_VALUE
(
char
,
int_value
,
CHAR
)
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
MakeValue
(
typename
WCharHelper
<
wchar_t
,
Char
>::
Supported
value
)
{
MakeValue
(
typename
WCharHelper
<
wchar_t
,
Char
>::
Supported
value
)
{
int_value
=
value
;
int_value
=
value
;
}
}
static
uint64_t
type
(
wchar_t
)
{
static
uint64_t
type
(
wchar_t
)
{
return
Arg
::
CHAR
;
return
Arg
::
CHAR
;
}
}
#endif
#endif
...
@@ -1271,44 +1397,51 @@ public:
...
@@ -1271,44 +1397,51 @@ public:
template
<
typename
T
>
template
<
typename
T
>
MakeValue
(
const
T
&
value
,
MakeValue
(
const
T
&
value
,
typename
EnableIf
<
Not
<
typename
EnableIf
<
Not
<
ConvertToInt
<
T
>::
value
>::
value
,
int
>::
type
=
0
)
{
ConvertToInt
<
T
>::
value
>::
value
,
int
>::
type
=
0
)
{
custom
.
value
=
&
value
;
custom
.
value
=
&
value
;
custom
.
format
=
&
format_custom_arg
<
T
>
;
custom
.
format
=
&
format_custom_arg
<
T
>
;
}
}
template
<
typename
T
>
template
<
typename
T
>
MakeValue
(
const
T
&
value
,
MakeValue
(
const
T
&
value
,
typename
EnableIf
<
ConvertToInt
<
T
>::
value
,
int
>::
type
=
0
)
{
typename
EnableIf
<
ConvertToInt
<
T
>::
value
,
int
>::
type
=
0
)
{
int_value
=
value
;
int_value
=
value
;
}
}
template
<
typename
T
>
template
<
typename
T
>
static
uint64_t
type
(
const
T
&
)
{
static
uint64_t
type
(
const
T
&
)
{
return
ConvertToInt
<
T
>::
value
?
Arg
::
INT
:
Arg
::
CUSTOM
;
return
ConvertToInt
<
T
>::
value
?
Arg
::
INT
:
Arg
::
CUSTOM
;
}
}
// Additional template param `Char_` is needed here because make_type always
// Additional template param `Char_` is needed here because make_type always
// uses char.
// uses char.
template
<
typename
Char_
>
template
<
typename
Char_
>
MakeValue
(
const
NamedArg
<
Char_
>
&
value
)
{
MakeValue
(
const
NamedArg
<
Char_
>
&
value
)
{
pointer
=
&
value
;
pointer
=
&
value
;
}
}
template
<
typename
Char_
>
template
<
typename
Char_
>
static
uint64_t
type
(
const
NamedArg
<
Char_
>
&
)
{
static
uint64_t
type
(
const
NamedArg
<
Char_
>
&
)
{
return
Arg
::
NAMED_ARG
;
return
Arg
::
NAMED_ARG
;
}
}
};
};
template
<
typename
Char
>
template
<
typename
Char
>
struct
NamedArg
:
Arg
{
struct
NamedArg
:
Arg
{
BasicStringRef
<
Char
>
name
;
BasicStringRef
<
Char
>
name
;
typedef
internal
::
MakeValue
<
BasicFormatter
<
Char
>
>
MakeValue
;
typedef
internal
::
MakeValue
<
BasicFormatter
<
Char
>
>
MakeValue
;
template
<
typename
T
>
template
<
typename
T
>
NamedArg
(
BasicStringRef
<
Char
>
argname
,
const
T
&
value
)
NamedArg
(
BasicStringRef
<
Char
>
argname
,
const
T
&
value
)
:
Arg
(
MakeValue
(
value
)),
name
(
argname
)
{
:
Arg
(
MakeValue
(
value
)),
name
(
argname
)
{
type
=
static_cast
<
Arg
::
Type
>
(
MakeValue
::
type
(
value
));
type
=
static_cast
<
Arg
::
Type
>
(
MakeValue
::
type
(
value
));
}
}
};
};
...
@@ -1336,67 +1469,86 @@ struct NamedArg : Arg {
...
@@ -1336,67 +1469,86 @@ struct NamedArg : Arg {
// ArgVisitor uses the curiously recurring template pattern:
// ArgVisitor uses the curiously recurring template pattern:
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
template
<
typename
Impl
,
typename
Result
>
template
<
typename
Impl
,
typename
Result
>
class
ArgVisitor
{
class
ArgVisitor
{
public
:
public
:
void
report_unhandled_arg
()
{}
void
report_unhandled_arg
()
{}
Result
visit_unhandled_arg
()
{
Result
visit_unhandled_arg
()
{
FMT_DISPATCH
(
report_unhandled_arg
());
FMT_DISPATCH
(
report_unhandled_arg
());
return
Result
();
return
Result
();
}
}
Result
visit_int
(
int
value
)
{
Result
visit_int
(
int
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
}
Result
visit_long_long
(
LongLong
value
)
{
Result
visit_long_long
(
LongLong
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
}
Result
visit_uint
(
unsigned
value
)
{
Result
visit_uint
(
unsigned
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
}
Result
visit_ulong_long
(
ULongLong
value
)
{
Result
visit_ulong_long
(
ULongLong
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
}
Result
visit_bool
(
bool
value
)
{
Result
visit_bool
(
bool
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
}
Result
visit_char
(
int
value
)
{
Result
visit_char
(
int
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
}
template
<
typename
T
>
template
<
typename
T
>
Result
visit_any_int
(
T
)
{
Result
visit_any_int
(
T
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit_double
(
double
value
)
{
Result
visit_double
(
double
value
)
{
return
FMT_DISPATCH
(
visit_any_double
(
value
));
return
FMT_DISPATCH
(
visit_any_double
(
value
));
}
}
Result
visit_long_double
(
long
double
value
)
{
Result
visit_long_double
(
long
double
value
)
{
return
FMT_DISPATCH
(
visit_any_double
(
value
));
return
FMT_DISPATCH
(
visit_any_double
(
value
));
}
}
template
<
typename
T
>
template
<
typename
T
>
Result
visit_any_double
(
T
)
{
Result
visit_any_double
(
T
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit_cstring
(
const
char
*
)
{
Result
visit_cstring
(
const
char
*
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit_string
(
Arg
::
StringValue
<
char
>
)
{
Result
visit_string
(
Arg
::
StringValue
<
char
>
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit_wstring
(
Arg
::
StringValue
<
wchar_t
>
)
{
Result
visit_wstring
(
Arg
::
StringValue
<
wchar_t
>
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit_pointer
(
const
void
*
)
{
Result
visit_pointer
(
const
void
*
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit_custom
(
Arg
::
CustomValue
)
{
Result
visit_custom
(
Arg
::
CustomValue
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit
(
const
Arg
&
arg
)
{
Result
visit
(
const
Arg
&
arg
)
switch
(
arg
.
type
)
{
{
switch
(
arg
.
type
)
{
default
:
default
:
FMT_ASSERT
(
false
,
"invalid argument type"
);
FMT_ASSERT
(
false
,
"invalid argument type"
);
return
Result
();
return
Result
();
...
@@ -1430,7 +1582,8 @@ public:
...
@@ -1430,7 +1582,8 @@ public:
}
}
};
};
class
RuntimeError
:
public
std
::
runtime_error
{
class
RuntimeError
:
public
std
::
runtime_error
{
protected
:
protected
:
RuntimeError
()
:
std
::
runtime_error
(
""
)
{}
RuntimeError
()
:
std
::
runtime_error
(
""
)
{}
};
};
...
@@ -1443,12 +1596,14 @@ class ArgMap;
...
@@ -1443,12 +1596,14 @@ class ArgMap;
}
// namespace internal
}
// namespace internal
/** An argument list. */
/** An argument list. */
class
ArgList
{
class
ArgList
{
private
:
private
:
// To reduce compiled code size per formatting function call, types of first
// To reduce compiled code size per formatting function call, types of first
// MAX_PACKED_ARGS arguments are passed in the types_ field.
// MAX_PACKED_ARGS arguments are passed in the types_ field.
uint64_t
types_
;
uint64_t
types_
;
union
{
union
{
// If the number of arguments is less than MAX_PACKED_ARGS, the argument
// If the number of arguments is less than MAX_PACKED_ARGS, the argument
// values are stored in values_, otherwise they are stored in args_.
// values are stored in values_, otherwise they are stored in args_.
// This is done to reduce compiled code size as storing larger objects
// This is done to reduce compiled code size as storing larger objects
...
@@ -1458,7 +1613,8 @@ private:
...
@@ -1458,7 +1613,8 @@ private:
const
internal
::
Arg
*
args_
;
const
internal
::
Arg
*
args_
;
};
};
internal
::
Arg
::
Type
type
(
unsigned
index
)
const
{
internal
::
Arg
::
Type
type
(
unsigned
index
)
const
{
unsigned
shift
=
index
*
4
;
unsigned
shift
=
index
*
4
;
uint64_t
mask
=
0xf
;
uint64_t
mask
=
0xf
;
return
static_cast
<
internal
::
Arg
::
Type
>
(
return
static_cast
<
internal
::
Arg
::
Type
>
(
...
@@ -1480,11 +1636,13 @@ public:
...
@@ -1480,11 +1636,13 @@ public:
:
types_
(
types
),
args_
(
args
)
{}
:
types_
(
types
),
args_
(
args
)
{}
/** Returns the argument at specified index. */
/** Returns the argument at specified index. */
internal
::
Arg
operator
[](
unsigned
index
)
const
{
internal
::
Arg
operator
[](
unsigned
index
)
const
{
using
internal
::
Arg
;
using
internal
::
Arg
;
Arg
arg
;
Arg
arg
;
bool
use_values
=
type
(
MAX_PACKED_ARGS
-
1
)
==
Arg
::
NONE
;
bool
use_values
=
type
(
MAX_PACKED_ARGS
-
1
)
==
Arg
::
NONE
;
if
(
index
<
MAX_PACKED_ARGS
)
{
if
(
index
<
MAX_PACKED_ARGS
)
{
Arg
::
Type
arg_type
=
type
(
index
);
Arg
::
Type
arg_type
=
type
(
index
);
internal
::
Value
&
val
=
arg
;
internal
::
Value
&
val
=
arg
;
if
(
arg_type
!=
Arg
::
NONE
)
if
(
arg_type
!=
Arg
::
NONE
)
...
@@ -1492,13 +1650,15 @@ public:
...
@@ -1492,13 +1650,15 @@ public:
arg
.
type
=
arg_type
;
arg
.
type
=
arg_type
;
return
arg
;
return
arg
;
}
}
if
(
use_values
)
{
if
(
use_values
)
{
// The index is greater than the number of arguments that can be stored
// The index is greater than the number of arguments that can be stored
// in values, so return a "none" argument.
// in values, so return a "none" argument.
arg
.
type
=
Arg
::
NONE
;
arg
.
type
=
Arg
::
NONE
;
return
arg
;
return
arg
;
}
}
for
(
unsigned
i
=
MAX_PACKED_ARGS
;
i
<=
index
;
++
i
)
{
for
(
unsigned
i
=
MAX_PACKED_ARGS
;
i
<=
index
;
++
i
)
{
if
(
args_
[
i
].
type
==
Arg
::
NONE
)
if
(
args_
[
i
].
type
==
Arg
::
NONE
)
return
args_
[
i
];
return
args_
[
i
];
}
}
...
@@ -1506,12 +1666,14 @@ public:
...
@@ -1506,12 +1666,14 @@ public:
}
}
};
};
enum
Alignment
{
enum
Alignment
{
ALIGN_DEFAULT
,
ALIGN_LEFT
,
ALIGN_RIGHT
,
ALIGN_CENTER
,
ALIGN_NUMERIC
ALIGN_DEFAULT
,
ALIGN_LEFT
,
ALIGN_RIGHT
,
ALIGN_CENTER
,
ALIGN_NUMERIC
};
};
// Flags.
// Flags.
enum
{
enum
{
SIGN_FLAG
=
1
,
PLUS_FLAG
=
2
,
MINUS_FLAG
=
4
,
HASH_FLAG
=
8
,
SIGN_FLAG
=
1
,
PLUS_FLAG
=
2
,
MINUS_FLAG
=
4
,
HASH_FLAG
=
8
,
CHAR_FLAG
=
0x10
// Argument has char type - used in error reporting.
CHAR_FLAG
=
0x10
// Argument has char type - used in error reporting.
};
};
...
@@ -1521,29 +1683,37 @@ struct EmptySpec {};
...
@@ -1521,29 +1683,37 @@ struct EmptySpec {};
// A type specifier.
// A type specifier.
template
<
char
TYPE
>
template
<
char
TYPE
>
struct
TypeSpec
:
EmptySpec
{
struct
TypeSpec
:
EmptySpec
Alignment
align
()
const
{
{
Alignment
align
()
const
{
return
ALIGN_DEFAULT
;
return
ALIGN_DEFAULT
;
}
}
unsigned
width
()
const
{
unsigned
width
()
const
{
return
0
;
return
0
;
}
}
int
precision
()
const
{
int
precision
()
const
{
return
-
1
;
return
-
1
;
}
}
bool
flag
(
unsigned
)
const
{
bool
flag
(
unsigned
)
const
{
return
false
;
return
false
;
}
}
char
type
()
const
{
char
type
()
const
{
return
TYPE
;
return
TYPE
;
}
}
char
fill
()
const
{
char
fill
()
const
{
return
' '
;
return
' '
;
}
}
};
};
// A width specifier.
// A width specifier.
struct
WidthSpec
{
struct
WidthSpec
{
unsigned
width_
;
unsigned
width_
;
// Fill is always wchar_t and cast to char if necessary to avoid having
// Fill is always wchar_t and cast to char if necessary to avoid having
// two specialization of WidthSpec and its subclasses.
// two specialization of WidthSpec and its subclasses.
...
@@ -1551,45 +1721,54 @@ struct WidthSpec {
...
@@ -1551,45 +1721,54 @@ struct WidthSpec {
WidthSpec
(
unsigned
width
,
wchar_t
fill
)
:
width_
(
width
),
fill_
(
fill
)
{}
WidthSpec
(
unsigned
width
,
wchar_t
fill
)
:
width_
(
width
),
fill_
(
fill
)
{}
unsigned
width
()
const
{
unsigned
width
()
const
{
return
width_
;
return
width_
;
}
}
wchar_t
fill
()
const
{
wchar_t
fill
()
const
{
return
fill_
;
return
fill_
;
}
}
};
};
// An alignment specifier.
// An alignment specifier.
struct
AlignSpec
:
WidthSpec
{
struct
AlignSpec
:
WidthSpec
{
Alignment
align_
;
Alignment
align_
;
AlignSpec
(
unsigned
width
,
wchar_t
fill
,
Alignment
align
=
ALIGN_DEFAULT
)
AlignSpec
(
unsigned
width
,
wchar_t
fill
,
Alignment
align
=
ALIGN_DEFAULT
)
:
WidthSpec
(
width
,
fill
),
align_
(
align
)
{}
:
WidthSpec
(
width
,
fill
),
align_
(
align
)
{}
Alignment
align
()
const
{
Alignment
align
()
const
{
return
align_
;
return
align_
;
}
}
int
precision
()
const
{
int
precision
()
const
{
return
-
1
;
return
-
1
;
}
}
};
};
// An alignment and type specifier.
// An alignment and type specifier.
template
<
char
TYPE
>
template
<
char
TYPE
>
struct
AlignTypeSpec
:
AlignSpec
{
struct
AlignTypeSpec
:
AlignSpec
{
AlignTypeSpec
(
unsigned
width
,
wchar_t
fill
)
:
AlignSpec
(
width
,
fill
)
{}
AlignTypeSpec
(
unsigned
width
,
wchar_t
fill
)
:
AlignSpec
(
width
,
fill
)
{}
bool
flag
(
unsigned
)
const
{
bool
flag
(
unsigned
)
const
{
return
false
;
return
false
;
}
}
char
type
()
const
{
char
type
()
const
{
return
TYPE
;
return
TYPE
;
}
}
};
};
// A full format specifier.
// A full format specifier.
struct
FormatSpec
:
AlignSpec
{
struct
FormatSpec
:
AlignSpec
{
unsigned
flags_
;
unsigned
flags_
;
int
precision_
;
int
precision_
;
char
type_
;
char
type_
;
...
@@ -1598,20 +1777,24 @@ struct FormatSpec : AlignSpec {
...
@@ -1598,20 +1777,24 @@ struct FormatSpec : AlignSpec {
unsigned
width
=
0
,
char
type
=
0
,
wchar_t
fill
=
' '
)
unsigned
width
=
0
,
char
type
=
0
,
wchar_t
fill
=
' '
)
:
AlignSpec
(
width
,
fill
),
flags_
(
0
),
precision_
(
-
1
),
type_
(
type
)
{}
:
AlignSpec
(
width
,
fill
),
flags_
(
0
),
precision_
(
-
1
),
type_
(
type
)
{}
bool
flag
(
unsigned
f
)
const
{
bool
flag
(
unsigned
f
)
const
{
return
(
flags_
&
f
)
!=
0
;
return
(
flags_
&
f
)
!=
0
;
}
}
int
precision
()
const
{
int
precision
()
const
{
return
precision_
;
return
precision_
;
}
}
char
type
()
const
{
char
type
()
const
{
return
type_
;
return
type_
;
}
}
};
};
// An integer format specifier.
// An integer format specifier.
template
<
typename
T
,
typename
SpecT
=
TypeSpec
<
0
>
,
typename
Char
=
char
>
template
<
typename
T
,
typename
SpecT
=
TypeSpec
<
0
>
,
typename
Char
=
char
>
class
IntFormatSpec
:
public
SpecT
{
class
IntFormatSpec
:
public
SpecT
{
private
:
private
:
T
value_
;
T
value_
;
...
@@ -1619,25 +1802,29 @@ public:
...
@@ -1619,25 +1802,29 @@ public:
IntFormatSpec
(
T
val
,
const
SpecT
&
spec
=
SpecT
())
IntFormatSpec
(
T
val
,
const
SpecT
&
spec
=
SpecT
())
:
SpecT
(
spec
),
value_
(
val
)
{}
:
SpecT
(
spec
),
value_
(
val
)
{}
T
value
()
const
{
T
value
()
const
{
return
value_
;
return
value_
;
}
}
};
};
// A string format specifier.
// A string format specifier.
template
<
typename
Char
>
template
<
typename
Char
>
class
StrFormatSpec
:
public
AlignSpec
{
class
StrFormatSpec
:
public
AlignSpec
{
private
:
private
:
const
Char
*
str_
;
const
Char
*
str_
;
public
:
public
:
template
<
typename
FillChar
>
template
<
typename
FillChar
>
StrFormatSpec
(
const
Char
*
str
,
unsigned
width
,
FillChar
fill
)
StrFormatSpec
(
const
Char
*
str
,
unsigned
width
,
FillChar
fill
)
:
AlignSpec
(
width
,
fill
),
str_
(
str
)
{
:
AlignSpec
(
width
,
fill
),
str_
(
str
)
{
internal
::
CharTraits
<
Char
>::
convert
(
FillChar
());
internal
::
CharTraits
<
Char
>::
convert
(
FillChar
());
}
}
const
Char
*
str
()
const
{
const
Char
*
str
()
const
{
return
str_
;
return
str_
;
}
}
};
};
...
@@ -1752,19 +1939,23 @@ std::string s = str(MemoryWriter() << pad("abc", 8));
...
@@ -1752,19 +1939,23 @@ std::string s = str(MemoryWriter() << pad("abc", 8));
*/
*/
template
<
typename
Char
>
template
<
typename
Char
>
inline
StrFormatSpec
<
Char
>
pad
(
inline
StrFormatSpec
<
Char
>
pad
(
const
Char
*
str
,
unsigned
width
,
Char
fill
=
' '
)
{
const
Char
*
str
,
unsigned
width
,
Char
fill
=
' '
)
{
return
StrFormatSpec
<
Char
>
(
str
,
width
,
fill
);
return
StrFormatSpec
<
Char
>
(
str
,
width
,
fill
);
}
}
inline
StrFormatSpec
<
wchar_t
>
pad
(
inline
StrFormatSpec
<
wchar_t
>
pad
(
const
wchar_t
*
str
,
unsigned
width
,
char
fill
=
' '
)
{
const
wchar_t
*
str
,
unsigned
width
,
char
fill
=
' '
)
{
return
StrFormatSpec
<
wchar_t
>
(
str
,
width
,
fill
);
return
StrFormatSpec
<
wchar_t
>
(
str
,
width
,
fill
);
}
}
namespace
internal
{
namespace
internal
{
template
<
typename
Char
>
template
<
typename
Char
>
class
ArgMap
{
class
ArgMap
{
private
:
private
:
typedef
std
::
map
<
fmt
::
BasicStringRef
<
Char
>
,
internal
::
Arg
>
MapType
;
typedef
std
::
map
<
fmt
::
BasicStringRef
<
Char
>
,
internal
::
Arg
>
MapType
;
typedef
typename
MapType
::
value_type
Pair
;
typedef
typename
MapType
::
value_type
Pair
;
...
@@ -1774,41 +1965,48 @@ private:
...
@@ -1774,41 +1965,48 @@ private:
public
:
public
:
FMT_API
void
init
(
const
ArgList
&
args
);
FMT_API
void
init
(
const
ArgList
&
args
);
const
internal
::
Arg
*
find
(
const
fmt
::
BasicStringRef
<
Char
>
&
name
)
const
{
const
internal
::
Arg
*
find
(
const
fmt
::
BasicStringRef
<
Char
>
&
name
)
const
{
typename
MapType
::
const_iterator
it
=
map_
.
find
(
name
);
typename
MapType
::
const_iterator
it
=
map_
.
find
(
name
);
return
it
!=
map_
.
end
()
?
&
it
->
second
:
0
;
return
it
!=
map_
.
end
()
?
&
it
->
second
:
0
;
}
}
};
};
template
<
typename
Impl
,
typename
Char
>
template
<
typename
Impl
,
typename
Char
>
class
ArgFormatterBase
:
public
ArgVisitor
<
Impl
,
void
>
{
class
ArgFormatterBase
:
public
ArgVisitor
<
Impl
,
void
>
{
private
:
private
:
BasicWriter
<
Char
>
&
writer_
;
BasicWriter
<
Char
>
&
writer_
;
FormatSpec
&
spec_
;
FormatSpec
&
spec_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
ArgFormatterBase
);
FMT_DISALLOW_COPY_AND_ASSIGN
(
ArgFormatterBase
);
void
write_pointer
(
const
void
*
p
)
{
void
write_pointer
(
const
void
*
p
)
{
spec_
.
flags_
=
HASH_FLAG
;
spec_
.
flags_
=
HASH_FLAG
;
spec_
.
type_
=
'x'
;
spec_
.
type_
=
'x'
;
writer_
.
write_int
(
reinterpret_cast
<
uintptr_t
>
(
p
),
spec_
);
writer_
.
write_int
(
reinterpret_cast
<
uintptr_t
>
(
p
),
spec_
);
}
}
protected
:
protected
:
BasicWriter
<
Char
>
&
writer
()
{
BasicWriter
<
Char
>
&
writer
()
{
return
writer_
;
return
writer_
;
}
}
FormatSpec
&
spec
()
{
FormatSpec
&
spec
()
{
return
spec_
;
return
spec_
;
}
}
void
write
(
bool
value
)
{
void
write
(
bool
value
)
{
const
char
*
str_value
=
value
?
"true"
:
"false"
;
const
char
*
str_value
=
value
?
"true"
:
"false"
;
Arg
::
StringValue
<
char
>
str
=
{
str_value
,
std
::
strlen
(
str_value
)
};
Arg
::
StringValue
<
char
>
str
=
{
str_value
,
std
::
strlen
(
str_value
)
};
writer_
.
write_str
(
str
,
spec_
);
writer_
.
write_str
(
str
,
spec_
);
}
}
void
write
(
const
char
*
value
)
{
void
write
(
const
char
*
value
)
{
Arg
::
StringValue
<
char
>
str
=
{
value
,
value
!=
0
?
std
::
strlen
(
value
)
:
0
};
Arg
::
StringValue
<
char
>
str
=
{
value
,
value
!=
0
?
std
::
strlen
(
value
)
:
0
};
writer_
.
write_str
(
str
,
spec_
);
writer_
.
write_str
(
str
,
spec_
);
}
}
...
@@ -1818,23 +2016,28 @@ public:
...
@@ -1818,23 +2016,28 @@ public:
:
writer_
(
w
),
spec_
(
s
)
{}
:
writer_
(
w
),
spec_
(
s
)
{}
template
<
typename
T
>
template
<
typename
T
>
void
visit_any_int
(
T
value
)
{
void
visit_any_int
(
T
value
)
{
writer_
.
write_int
(
value
,
spec_
);
writer_
.
write_int
(
value
,
spec_
);
}
}
template
<
typename
T
>
template
<
typename
T
>
void
visit_any_double
(
T
value
)
{
void
visit_any_double
(
T
value
)
{
writer_
.
write_double
(
value
,
spec_
);
writer_
.
write_double
(
value
,
spec_
);
}
}
void
visit_bool
(
bool
value
)
{
void
visit_bool
(
bool
value
)
{
if
(
spec_
.
type_
)
if
(
spec_
.
type_
)
return
visit_any_int
(
value
);
return
visit_any_int
(
value
);
write
(
value
);
write
(
value
);
}
}
void
visit_char
(
int
value
)
{
void
visit_char
(
int
value
)
if
(
spec_
.
type_
&&
spec_
.
type_
!=
'c'
)
{
{
if
(
spec_
.
type_
&&
spec_
.
type_
!=
'c'
)
{
spec_
.
flags_
|=
CHAR_FLAG
;
spec_
.
flags_
|=
CHAR_FLAG
;
writer_
.
write_int
(
value
,
spec_
);
writer_
.
write_int
(
value
,
spec_
);
return
;
return
;
...
@@ -1845,44 +2048,53 @@ public:
...
@@ -1845,44 +2048,53 @@ public:
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec_
.
fill
());
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec_
.
fill
());
CharPtr
out
=
CharPtr
();
CharPtr
out
=
CharPtr
();
const
unsigned
CHAR_WIDTH
=
1
;
const
unsigned
CHAR_WIDTH
=
1
;
if
(
spec_
.
width_
>
CHAR_WIDTH
)
{
if
(
spec_
.
width_
>
CHAR_WIDTH
)
{
out
=
writer_
.
grow_buffer
(
spec_
.
width_
);
out
=
writer_
.
grow_buffer
(
spec_
.
width_
);
if
(
spec_
.
align_
==
ALIGN_RIGHT
)
{
if
(
spec_
.
align_
==
ALIGN_RIGHT
)
{
std
::
uninitialized_fill_n
(
out
,
spec_
.
width_
-
CHAR_WIDTH
,
fill
);
std
::
uninitialized_fill_n
(
out
,
spec_
.
width_
-
CHAR_WIDTH
,
fill
);
out
+=
spec_
.
width_
-
CHAR_WIDTH
;
out
+=
spec_
.
width_
-
CHAR_WIDTH
;
}
}
else
if
(
spec_
.
align_
==
ALIGN_CENTER
)
{
else
if
(
spec_
.
align_
==
ALIGN_CENTER
)
{
out
=
writer_
.
fill_padding
(
out
,
spec_
.
width_
,
out
=
writer_
.
fill_padding
(
out
,
spec_
.
width_
,
internal
::
check
(
CHAR_WIDTH
),
fill
);
internal
::
check
(
CHAR_WIDTH
),
fill
);
}
}
else
{
else
{
std
::
uninitialized_fill_n
(
out
+
CHAR_WIDTH
,
std
::
uninitialized_fill_n
(
out
+
CHAR_WIDTH
,
spec_
.
width_
-
CHAR_WIDTH
,
fill
);
spec_
.
width_
-
CHAR_WIDTH
,
fill
);
}
}
}
}
else
{
else
{
out
=
writer_
.
grow_buffer
(
CHAR_WIDTH
);
out
=
writer_
.
grow_buffer
(
CHAR_WIDTH
);
}
}
*
out
=
internal
::
CharTraits
<
Char
>::
cast
(
value
);
*
out
=
internal
::
CharTraits
<
Char
>::
cast
(
value
);
}
}
void
visit_cstring
(
const
char
*
value
)
{
void
visit_cstring
(
const
char
*
value
)
{
if
(
spec_
.
type_
==
'p'
)
if
(
spec_
.
type_
==
'p'
)
return
write_pointer
(
value
);
return
write_pointer
(
value
);
write
(
value
);
write
(
value
);
}
}
void
visit_string
(
Arg
::
StringValue
<
char
>
value
)
{
void
visit_string
(
Arg
::
StringValue
<
char
>
value
)
{
writer_
.
write_str
(
value
,
spec_
);
writer_
.
write_str
(
value
,
spec_
);
}
}
using
ArgVisitor
<
Impl
,
void
>::
visit_wstring
;
using
ArgVisitor
<
Impl
,
void
>::
visit_wstring
;
void
visit_wstring
(
Arg
::
StringValue
<
Char
>
value
)
{
void
visit_wstring
(
Arg
::
StringValue
<
Char
>
value
)
{
writer_
.
write_str
(
value
,
spec_
);
writer_
.
write_str
(
value
,
spec_
);
}
}
void
visit_pointer
(
const
void
*
value
)
{
void
visit_pointer
(
const
void
*
value
)
{
if
(
spec_
.
type_
&&
spec_
.
type_
!=
'p'
)
if
(
spec_
.
type_
&&
spec_
.
type_
!=
'p'
)
report_unknown_type
(
spec_
.
type_
,
"pointer"
);
report_unknown_type
(
spec_
.
type_
,
"pointer"
);
write_pointer
(
value
);
write_pointer
(
value
);
...
@@ -1892,7 +2104,8 @@ public:
...
@@ -1892,7 +2104,8 @@ public:
// An argument formatter.
// An argument formatter.
template
<
typename
Char
>
template
<
typename
Char
>
class
BasicArgFormatter
:
class
BasicArgFormatter
:
public
ArgFormatterBase
<
BasicArgFormatter
<
Char
>
,
Char
>
{
public
ArgFormatterBase
<
BasicArgFormatter
<
Char
>
,
Char
>
{
private
:
private
:
BasicFormatter
<
Char
>
&
formatter_
;
BasicFormatter
<
Char
>
&
formatter_
;
const
Char
*
format_
;
const
Char
*
format_
;
...
@@ -1902,12 +2115,14 @@ public:
...
@@ -1902,12 +2115,14 @@ public:
:
ArgFormatterBase
<
BasicArgFormatter
<
Char
>
,
Char
>
(
f
.
writer
(),
s
),
:
ArgFormatterBase
<
BasicArgFormatter
<
Char
>
,
Char
>
(
f
.
writer
(),
s
),
formatter_
(
f
),
format_
(
fmt
)
{}
formatter_
(
f
),
format_
(
fmt
)
{}
void
visit_custom
(
Arg
::
CustomValue
c
)
{
void
visit_custom
(
Arg
::
CustomValue
c
)
{
c
.
format
(
&
formatter_
,
c
.
value
,
&
format_
);
c
.
format
(
&
formatter_
,
c
.
value
,
&
format_
);
}
}
};
};
class
FormatterBase
{
class
FormatterBase
{
private
:
private
:
ArgList
args_
;
ArgList
args_
;
int
next_arg_index_
;
int
next_arg_index_
;
...
@@ -1916,17 +2131,20 @@ private:
...
@@ -1916,17 +2131,20 @@ private:
FMT_API
Arg
do_get_arg
(
unsigned
arg_index
,
const
char
*&
error
);
FMT_API
Arg
do_get_arg
(
unsigned
arg_index
,
const
char
*&
error
);
protected
:
protected
:
const
ArgList
&
args
()
const
{
const
ArgList
&
args
()
const
{
return
args_
;
return
args_
;
}
}
explicit
FormatterBase
(
const
ArgList
&
args
)
{
explicit
FormatterBase
(
const
ArgList
&
args
)
{
args_
=
args
;
args_
=
args
;
next_arg_index_
=
0
;
next_arg_index_
=
0
;
}
}
// Returns the next argument.
// Returns the next argument.
Arg
next_arg
(
const
char
*&
error
)
{
Arg
next_arg
(
const
char
*&
error
)
{
if
(
next_arg_index_
>=
0
)
if
(
next_arg_index_
>=
0
)
return
do_get_arg
(
next_arg_index_
++
,
error
);
return
do_get_arg
(
next_arg_index_
++
,
error
);
error
=
"cannot switch from manual to automatic argument indexing"
;
error
=
"cannot switch from manual to automatic argument indexing"
;
...
@@ -1935,12 +2153,15 @@ protected:
...
@@ -1935,12 +2153,15 @@ protected:
// Checks if manual indexing is used and returns the argument with
// Checks if manual indexing is used and returns the argument with
// specified index.
// specified index.
Arg
get_arg
(
unsigned
arg_index
,
const
char
*&
error
)
{
Arg
get_arg
(
unsigned
arg_index
,
const
char
*&
error
)
{
return
check_no_auto_index
(
error
)
?
do_get_arg
(
arg_index
,
error
)
:
Arg
();
return
check_no_auto_index
(
error
)
?
do_get_arg
(
arg_index
,
error
)
:
Arg
();
}
}
bool
check_no_auto_index
(
const
char
*&
error
)
{
bool
check_no_auto_index
(
const
char
*&
error
)
if
(
next_arg_index_
>
0
)
{
{
if
(
next_arg_index_
>
0
)
{
error
=
"cannot switch from automatic to manual argument indexing"
;
error
=
"cannot switch from automatic to manual argument indexing"
;
return
false
;
return
false
;
}
}
...
@@ -1949,7 +2170,8 @@ protected:
...
@@ -1949,7 +2170,8 @@ protected:
}
}
template
<
typename
Char
>
template
<
typename
Char
>
void
write
(
BasicWriter
<
Char
>
&
w
,
const
Char
*
start
,
const
Char
*
end
)
{
void
write
(
BasicWriter
<
Char
>
&
w
,
const
Char
*
start
,
const
Char
*
end
)
{
if
(
start
!=
end
)
if
(
start
!=
end
)
w
<<
BasicStringRef
<
Char
>
(
start
,
end
-
start
);
w
<<
BasicStringRef
<
Char
>
(
start
,
end
-
start
);
}
}
...
@@ -1957,7 +2179,8 @@ protected:
...
@@ -1957,7 +2179,8 @@ protected:
// A printf formatter.
// A printf formatter.
template
<
typename
Char
>
template
<
typename
Char
>
class
PrintfFormatter
:
private
FormatterBase
{
class
PrintfFormatter
:
private
FormatterBase
{
private
:
private
:
void
parse_flags
(
FormatSpec
&
spec
,
const
Char
*&
s
);
void
parse_flags
(
FormatSpec
&
spec
,
const
Char
*&
s
);
...
@@ -1978,7 +2201,8 @@ public:
...
@@ -1978,7 +2201,8 @@ public:
// A formatter.
// A formatter.
template
<
typename
CharType
>
template
<
typename
CharType
>
class
BasicFormatter
:
private
internal
::
FormatterBase
{
class
BasicFormatter
:
private
internal
::
FormatterBase
{
public
:
public
:
typedef
CharType
Char
;
typedef
CharType
Char
;
...
@@ -2004,7 +2228,8 @@ public:
...
@@ -2004,7 +2228,8 @@ public:
BasicFormatter
(
const
ArgList
&
args
,
BasicWriter
<
Char
>
&
w
)
BasicFormatter
(
const
ArgList
&
args
,
BasicWriter
<
Char
>
&
w
)
:
internal
::
FormatterBase
(
args
),
writer_
(
w
)
{}
:
internal
::
FormatterBase
(
args
),
writer_
(
w
)
{}
BasicWriter
<
Char
>
&
writer
()
{
BasicWriter
<
Char
>
&
writer
()
{
return
writer_
;
return
writer_
;
}
}
...
@@ -2032,18 +2257,22 @@ public:
...
@@ -2032,18 +2257,22 @@ public:
# define FMT_GEN14(f) FMT_GEN13(f), f(13)
# define FMT_GEN14(f) FMT_GEN13(f), f(13)
# define FMT_GEN15(f) FMT_GEN14(f), f(14)
# define FMT_GEN15(f) FMT_GEN14(f), f(14)
namespace
internal
{
namespace
internal
inline
uint64_t
make_type
()
{
{
inline
uint64_t
make_type
()
{
return
0
;
return
0
;
}
}
template
<
typename
T
>
template
<
typename
T
>
inline
uint64_t
make_type
(
const
T
&
arg
)
{
inline
uint64_t
make_type
(
const
T
&
arg
)
{
return
MakeValue
<
BasicFormatter
<
char
>
>::
type
(
arg
);
return
MakeValue
<
BasicFormatter
<
char
>
>::
type
(
arg
);
}
}
template
<
unsigned
N
>
template
<
unsigned
N
>
struct
ArgArray
{
struct
ArgArray
{
// Computes the argument array size by adding 1 to N, which is the number of
// Computes the argument array size by adding 1 to N, which is the number of
// arguments, if N is zero, because array of zero size is invalid, or if N
// arguments, if N is zero, because array of zero size is invalid, or if N
// is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra
// is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra
...
@@ -2056,28 +2285,32 @@ struct ArgArray {
...
@@ -2056,28 +2285,32 @@ struct ArgArray {
#if FMT_USE_VARIADIC_TEMPLATES
#if FMT_USE_VARIADIC_TEMPLATES
template
<
typename
Arg
,
typename
...
Args
>
template
<
typename
Arg
,
typename
...
Args
>
inline
uint64_t
make_type
(
const
Arg
&
first
,
const
Args
&
...
tail
)
{
inline
uint64_t
make_type
(
const
Arg
&
first
,
const
Args
&
...
tail
)
{
return
make_type
(
first
)
|
(
make_type
(
tail
...)
<<
4
);
return
make_type
(
first
)
|
(
make_type
(
tail
...)
<<
4
);
}
}
inline
void
do_set_types
(
Arg
*
)
{}
inline
void
do_set_types
(
Arg
*
)
{}
template
<
typename
T
,
typename
...
Args
>
template
<
typename
T
,
typename
...
Args
>
inline
void
do_set_types
(
Arg
*
args
,
const
T
&
arg
,
const
Args
&
...
tail
)
{
inline
void
do_set_types
(
Arg
*
args
,
const
T
&
arg
,
const
Args
&
...
tail
)
{
args
->
type
=
static_cast
<
Arg
::
Type
>
(
args
->
type
=
static_cast
<
Arg
::
Type
>
(
MakeValue
<
BasicFormatter
<
char
>
>::
type
(
arg
));
MakeValue
<
BasicFormatter
<
char
>
>::
type
(
arg
));
do_set_types
(
args
+
1
,
tail
...);
do_set_types
(
args
+
1
,
tail
...);
}
}
template
<
typename
...
Args
>
template
<
typename
...
Args
>
inline
void
set_types
(
Arg
*
array
,
const
Args
&
...
args
)
{
inline
void
set_types
(
Arg
*
array
,
const
Args
&
...
args
)
{
if
(
check
(
sizeof
...(
Args
)
>
ArgList
::
MAX_PACKED_ARGS
))
if
(
check
(
sizeof
...(
Args
)
>
ArgList
::
MAX_PACKED_ARGS
))
do_set_types
(
array
,
args
...);
do_set_types
(
array
,
args
...);
array
[
sizeof
...(
Args
)].
type
=
Arg
::
NONE
;
array
[
sizeof
...(
Args
)].
type
=
Arg
::
NONE
;
}
}
template
<
typename
...
Args
>
template
<
typename
...
Args
>
inline
void
set_types
(
Value
*
,
const
Args
&
...)
{
inline
void
set_types
(
Value
*
,
const
Args
&
...)
{
// Do nothing as types are passed separately from values.
// Do nothing as types are passed separately from values.
}
}
...
@@ -2085,7 +2318,8 @@ template <typename Formatter, typename Value>
...
@@ -2085,7 +2318,8 @@ template <typename Formatter, typename Value>
inline
void
store_args
(
Value
*
)
{}
inline
void
store_args
(
Value
*
)
{}
template
<
typename
Formatter
,
typename
Arg
,
typename
T
,
typename
...
Args
>
template
<
typename
Formatter
,
typename
Arg
,
typename
T
,
typename
...
Args
>
inline
void
store_args
(
Arg
*
args
,
const
T
&
arg
,
const
Args
&
...
tail
)
{
inline
void
store_args
(
Arg
*
args
,
const
T
&
arg
,
const
Args
&
...
tail
)
{
// Assign only the Value subobject of Arg and don't overwrite type (if any)
// Assign only the Value subobject of Arg and don't overwrite type (if any)
// that is assigned by set_types.
// that is assigned by set_types.
Value
&
value
=
*
args
;
Value
&
value
=
*
args
;
...
@@ -2095,7 +2329,8 @@ inline void store_args(Arg *args, const T &arg, const Args & ... tail) {
...
@@ -2095,7 +2329,8 @@ inline void store_args(Arg *args, const T &arg, const Args & ... tail) {
template
<
typename
Formatter
,
typename
...
Args
>
template
<
typename
Formatter
,
typename
...
Args
>
ArgList
make_arg_list
(
typename
ArgArray
<
sizeof
...(
Args
)
>::
Type
array
,
ArgList
make_arg_list
(
typename
ArgArray
<
sizeof
...(
Args
)
>::
Type
array
,
const
Args
&
...
args
)
{
const
Args
&
...
args
)
{
if
(
check
(
sizeof
...(
Args
)
>=
ArgList
::
MAX_PACKED_ARGS
))
if
(
check
(
sizeof
...(
Args
)
>=
ArgList
::
MAX_PACKED_ARGS
))
set_types
(
array
,
args
...);
set_types
(
array
,
args
...);
store_args
<
Formatter
>
(
array
,
args
...);
store_args
<
Formatter
>
(
array
,
args
...);
...
@@ -2103,7 +2338,8 @@ ArgList make_arg_list(typename ArgArray<sizeof...(Args)>::Type array,
...
@@ -2103,7 +2338,8 @@ ArgList make_arg_list(typename ArgArray<sizeof...(Args)>::Type array,
}
}
#else
#else
struct
ArgType
{
struct
ArgType
{
uint64_t
type
;
uint64_t
type
;
ArgType
()
:
type
(
0
)
{}
ArgType
()
:
type
(
0
)
{}
...
@@ -2114,7 +2350,8 @@ struct ArgType {
...
@@ -2114,7 +2350,8 @@ struct ArgType {
# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType()
# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType()
inline
uint64_t
make_type
(
FMT_GEN15
(
FMT_ARG_TYPE_DEFAULT
))
{
inline
uint64_t
make_type
(
FMT_GEN15
(
FMT_ARG_TYPE_DEFAULT
))
{
return
t0
.
type
|
(
t1
.
type
<<
4
)
|
(
t2
.
type
<<
8
)
|
(
t3
.
type
<<
12
)
|
return
t0
.
type
|
(
t1
.
type
<<
4
)
|
(
t2
.
type
<<
8
)
|
(
t3
.
type
<<
12
)
|
(
t4
.
type
<<
16
)
|
(
t5
.
type
<<
20
)
|
(
t6
.
type
<<
24
)
|
(
t7
.
type
<<
28
)
|
(
t4
.
type
<<
16
)
|
(
t5
.
type
<<
20
)
|
(
t6
.
type
<<
24
)
|
(
t7
.
type
<<
28
)
|
(
t8
.
type
<<
32
)
|
(
t9
.
type
<<
36
)
|
(
t10
.
type
<<
40
)
|
(
t11
.
type
<<
44
)
|
(
t8
.
type
<<
32
)
|
(
t9
.
type
<<
36
)
|
(
t10
.
type
<<
40
)
|
(
t11
.
type
<<
44
)
|
...
@@ -2123,7 +2360,8 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
...
@@ -2123,7 +2360,8 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
#endif
#endif
template
<
class
Char
>
template
<
class
Char
>
class
FormatBuf
:
public
std
::
basic_streambuf
<
Char
>
{
class
FormatBuf
:
public
std
::
basic_streambuf
<
Char
>
{
private
:
private
:
typedef
typename
std
::
basic_streambuf
<
Char
>::
int_type
int_type
;
typedef
typename
std
::
basic_streambuf
<
Char
>::
int_type
int_type
;
typedef
typename
std
::
basic_streambuf
<
Char
>::
traits_type
traits_type
;
typedef
typename
std
::
basic_streambuf
<
Char
>::
traits_type
traits_type
;
...
@@ -2132,12 +2370,15 @@ private:
...
@@ -2132,12 +2370,15 @@ private:
Char
*
start_
;
Char
*
start_
;
public
:
public
:
FormatBuf
(
Buffer
<
Char
>
&
buffer
)
:
buffer_
(
buffer
),
start_
(
&
buffer
[
0
])
{
FormatBuf
(
Buffer
<
Char
>
&
buffer
)
:
buffer_
(
buffer
),
start_
(
&
buffer
[
0
])
{
this
->
setp
(
start_
,
start_
+
buffer_
.
capacity
());
this
->
setp
(
start_
,
start_
+
buffer_
.
capacity
());
}
}
int_type
overflow
(
int_type
ch
=
traits_type
::
eof
())
{
int_type
overflow
(
int_type
ch
=
traits_type
::
eof
())
if
(
!
traits_type
::
eq_int_type
(
ch
,
traits_type
::
eof
()))
{
{
if
(
!
traits_type
::
eq_int_type
(
ch
,
traits_type
::
eof
()))
{
size_t
size
=
this
->
pptr
()
-
start_
;
size_t
size
=
this
->
pptr
()
-
start_
;
buffer_
.
resize
(
size
);
buffer_
.
resize
(
size
);
buffer_
.
reserve
(
size
*
2
);
buffer_
.
reserve
(
size
*
2
);
...
@@ -2149,7 +2390,8 @@ public:
...
@@ -2149,7 +2390,8 @@ public:
return
ch
;
return
ch
;
}
}
size_t
size
()
const
{
size_t
size
()
const
{
return
this
->
pptr
()
-
start_
;
return
this
->
pptr
()
-
start_
;
}
}
};
};
...
@@ -2255,7 +2497,8 @@ public:
...
@@ -2255,7 +2497,8 @@ public:
An error returned by an operating system or a language runtime,
An error returned by an operating system or a language runtime,
for example a file opening error.
for example a file opening error.
*/
*/
class
SystemError
:
public
internal
::
RuntimeError
{
class
SystemError
:
public
internal
::
RuntimeError
{
private
:
private
:
void
init
(
int
err_code
,
CStringRef
format_str
,
ArgList
args
);
void
init
(
int
err_code
,
CStringRef
format_str
,
ArgList
args
);
...
@@ -2292,12 +2535,14 @@ public:
...
@@ -2292,12 +2535,14 @@ public:
throw fmt::SystemError(errno, "cannot open file '{}'", filename);
throw fmt::SystemError(errno, "cannot open file '{}'", filename);
\endrst
\endrst
*/
*/
SystemError
(
int
error_code
,
CStringRef
message
)
{
SystemError
(
int
error_code
,
CStringRef
message
)
{
init
(
error_code
,
message
,
ArgList
());
init
(
error_code
,
message
,
ArgList
());
}
}
FMT_VARIADIC_CTOR
(
SystemError
,
init
,
int
,
CStringRef
)
FMT_VARIADIC_CTOR
(
SystemError
,
init
,
int
,
CStringRef
)
int
error_code
()
const
{
int
error_code
()
const
{
return
error_code_
;
return
error_code_
;
}
}
};
};
...
@@ -2321,7 +2566,8 @@ You can use one of the following typedefs for common character types:
...
@@ -2321,7 +2566,8 @@ You can use one of the following typedefs for common character types:
\endrst
\endrst
*/
*/
template
<
typename
Char
>
template
<
typename
Char
>
class
BasicWriter
{
class
BasicWriter
{
private
:
private
:
// Output buffer.
// Output buffer.
Buffer
<
Char
>
&
buffer_
;
Buffer
<
Char
>
&
buffer_
;
...
@@ -2332,11 +2578,13 @@ private:
...
@@ -2332,11 +2578,13 @@ private:
#if FMT_SECURE_SCL
#if FMT_SECURE_SCL
// Returns pointer value.
// Returns pointer value.
static
Char
*
get
(
CharPtr
p
)
{
static
Char
*
get
(
CharPtr
p
)
{
return
p
.
base
();
return
p
.
base
();
}
}
#else
#else
static
Char
*
get
(
Char
*
p
)
{
static
Char
*
get
(
Char
*
p
)
{
return
p
;
return
p
;
}
}
#endif
#endif
...
@@ -2348,7 +2596,8 @@ private:
...
@@ -2348,7 +2596,8 @@ private:
// Grows the buffer by n characters and returns a pointer to the newly
// Grows the buffer by n characters and returns a pointer to the newly
// allocated area.
// allocated area.
CharPtr
grow_buffer
(
std
::
size_t
n
)
{
CharPtr
grow_buffer
(
std
::
size_t
n
)
{
std
::
size_t
size
=
buffer_
.
size
();
std
::
size_t
size
=
buffer_
.
size
();
buffer_
.
resize
(
size
+
n
);
buffer_
.
resize
(
size
+
n
);
return
internal
::
make_ptr
(
&
buffer_
[
size
],
n
);
return
internal
::
make_ptr
(
&
buffer_
[
size
],
n
);
...
@@ -2356,7 +2605,8 @@ private:
...
@@ -2356,7 +2605,8 @@ private:
// Writes an unsigned decimal integer.
// Writes an unsigned decimal integer.
template
<
typename
UInt
>
template
<
typename
UInt
>
Char
*
write_unsigned_decimal
(
UInt
value
,
unsigned
prefix_size
=
0
)
{
Char
*
write_unsigned_decimal
(
UInt
value
,
unsigned
prefix_size
=
0
)
{
unsigned
num_digits
=
internal
::
count_digits
(
value
);
unsigned
num_digits
=
internal
::
count_digits
(
value
);
Char
*
ptr
=
get
(
grow_buffer
(
prefix_size
+
num_digits
));
Char
*
ptr
=
get
(
grow_buffer
(
prefix_size
+
num_digits
));
internal
::
format_decimal
(
ptr
+
prefix_size
,
value
,
num_digits
);
internal
::
format_decimal
(
ptr
+
prefix_size
,
value
,
num_digits
);
...
@@ -2365,20 +2615,24 @@ private:
...
@@ -2365,20 +2615,24 @@ private:
// Writes a decimal integer.
// Writes a decimal integer.
template
<
typename
Int
>
template
<
typename
Int
>
void
write_decimal
(
Int
value
)
{
void
write_decimal
(
Int
value
)
{
typename
internal
::
IntTraits
<
Int
>::
MainType
abs_value
=
value
;
typename
internal
::
IntTraits
<
Int
>::
MainType
abs_value
=
value
;
if
(
internal
::
is_negative
(
value
))
{
if
(
internal
::
is_negative
(
value
))
{
abs_value
=
0
-
abs_value
;
abs_value
=
0
-
abs_value
;
*
write_unsigned_decimal
(
abs_value
,
1
)
=
'-'
;
*
write_unsigned_decimal
(
abs_value
,
1
)
=
'-'
;
}
}
else
{
else
{
write_unsigned_decimal
(
abs_value
,
0
);
write_unsigned_decimal
(
abs_value
,
0
);
}
}
}
}
// Prepare a buffer for integer formatting.
// Prepare a buffer for integer formatting.
CharPtr
prepare_int_buffer
(
unsigned
num_digits
,
CharPtr
prepare_int_buffer
(
unsigned
num_digits
,
const
EmptySpec
&
,
const
char
*
prefix
,
unsigned
prefix_size
)
{
const
EmptySpec
&
,
const
char
*
prefix
,
unsigned
prefix_size
)
{
unsigned
size
=
prefix_size
+
num_digits
;
unsigned
size
=
prefix_size
+
num_digits
;
CharPtr
p
=
grow_buffer
(
size
);
CharPtr
p
=
grow_buffer
(
size
);
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
p
);
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
p
);
...
@@ -2415,7 +2669,8 @@ private:
...
@@ -2415,7 +2669,8 @@ private:
// Appends floating-point length specifier to the format string.
// Appends floating-point length specifier to the format string.
// The second argument is only used for overload resolution.
// The second argument is only used for overload resolution.
void
append_float_length
(
Char
*&
format_ptr
,
long
double
)
{
void
append_float_length
(
Char
*&
format_ptr
,
long
double
)
{
*
format_ptr
++
=
'L'
;
*
format_ptr
++
=
'L'
;
}
}
...
@@ -2444,7 +2699,8 @@ public:
...
@@ -2444,7 +2699,8 @@ public:
/**
/**
Returns the total number of characters written.
Returns the total number of characters written.
*/
*/
std
::
size_t
size
()
const
{
std
::
size_t
size
()
const
{
return
buffer_
.
size
();
return
buffer_
.
size
();
}
}
...
@@ -2452,7 +2708,8 @@ public:
...
@@ -2452,7 +2708,8 @@ public:
Returns a pointer to the output buffer content. No terminating null
Returns a pointer to the output buffer content. No terminating null
character is appended.
character is appended.
*/
*/
const
Char
*
data
()
const
FMT_NOEXCEPT
{
const
Char
*
data
()
const
FMT_NOEXCEPT
{
return
&
buffer_
[
0
];
return
&
buffer_
[
0
];
}
}
...
@@ -2460,7 +2717,8 @@ public:
...
@@ -2460,7 +2717,8 @@ public:
Returns a pointer to the output buffer content with terminating null
Returns a pointer to the output buffer content with terminating null
character appended.
character appended.
*/
*/
const
Char
*
c_str
()
const
{
const
Char
*
c_str
()
const
{
std
::
size_t
size
=
buffer_
.
size
();
std
::
size_t
size
=
buffer_
.
size
();
buffer_
.
reserve
(
size
+
1
);
buffer_
.
reserve
(
size
+
1
);
buffer_
[
size
]
=
'\0'
;
buffer_
[
size
]
=
'\0'
;
...
@@ -2472,7 +2730,8 @@ public:
...
@@ -2472,7 +2730,8 @@ public:
Returns the content of the output buffer as an `std::string`.
Returns the content of the output buffer as an `std::string`.
\endrst
\endrst
*/
*/
std
::
basic_string
<
Char
>
str
()
const
{
std
::
basic_string
<
Char
>
str
()
const
{
return
std
::
basic_string
<
Char
>
(
&
buffer_
[
0
],
buffer_
.
size
());
return
std
::
basic_string
<
Char
>
(
&
buffer_
[
0
],
buffer_
.
size
());
}
}
...
@@ -2501,26 +2760,32 @@ public:
...
@@ -2501,26 +2760,32 @@ public:
See also :ref:`syntax`.
See also :ref:`syntax`.
\endrst
\endrst
*/
*/
void
write
(
BasicCStringRef
<
Char
>
format
,
ArgList
args
)
{
void
write
(
BasicCStringRef
<
Char
>
format
,
ArgList
args
)
{
BasicFormatter
<
Char
>
(
args
,
*
this
).
format
(
format
);
BasicFormatter
<
Char
>
(
args
,
*
this
).
format
(
format
);
}
}
FMT_VARIADIC_VOID
(
write
,
BasicCStringRef
<
Char
>
)
FMT_VARIADIC_VOID
(
write
,
BasicCStringRef
<
Char
>
)
BasicWriter
&
operator
<<
(
int
value
)
{
BasicWriter
&
operator
<<
(
int
value
)
{
write_decimal
(
value
);
write_decimal
(
value
);
return
*
this
;
return
*
this
;
}
}
BasicWriter
&
operator
<<
(
unsigned
value
)
{
BasicWriter
&
operator
<<
(
unsigned
value
)
{
return
*
this
<<
IntFormatSpec
<
unsigned
>
(
value
);
return
*
this
<<
IntFormatSpec
<
unsigned
>
(
value
);
}
}
BasicWriter
&
operator
<<
(
long
value
)
{
BasicWriter
&
operator
<<
(
long
value
)
{
write_decimal
(
value
);
write_decimal
(
value
);
return
*
this
;
return
*
this
;
}
}
BasicWriter
&
operator
<<
(
unsigned
long
value
)
{
BasicWriter
&
operator
<<
(
unsigned
long
value
)
{
return
*
this
<<
IntFormatSpec
<
unsigned
long
>
(
value
);
return
*
this
<<
IntFormatSpec
<
unsigned
long
>
(
value
);
}
}
BasicWriter
&
operator
<<
(
LongLong
value
)
{
BasicWriter
&
operator
<<
(
LongLong
value
)
{
write_decimal
(
value
);
write_decimal
(
value
);
return
*
this
;
return
*
this
;
}
}
...
@@ -2530,11 +2795,13 @@ public:
...
@@ -2530,11 +2795,13 @@ public:
Formats *value* and writes it to the stream.
Formats *value* and writes it to the stream.
\endrst
\endrst
*/
*/
BasicWriter
&
operator
<<
(
ULongLong
value
)
{
BasicWriter
&
operator
<<
(
ULongLong
value
)
{
return
*
this
<<
IntFormatSpec
<
ULongLong
>
(
value
);
return
*
this
<<
IntFormatSpec
<
ULongLong
>
(
value
);
}
}
BasicWriter
&
operator
<<
(
double
value
)
{
BasicWriter
&
operator
<<
(
double
value
)
{
write_double
(
value
,
FormatSpec
());
write_double
(
value
,
FormatSpec
());
return
*
this
;
return
*
this
;
}
}
...
@@ -2545,7 +2812,8 @@ public:
...
@@ -2545,7 +2812,8 @@ public:
(``'g'``) and writes it to the stream.
(``'g'``) and writes it to the stream.
\endrst
\endrst
*/
*/
BasicWriter
&
operator
<<
(
long
double
value
)
{
BasicWriter
&
operator
<<
(
long
double
value
)
{
write_double
(
value
,
FormatSpec
());
write_double
(
value
,
FormatSpec
());
return
*
this
;
return
*
this
;
}
}
...
@@ -2553,13 +2821,15 @@ public:
...
@@ -2553,13 +2821,15 @@ public:
/**
/**
Writes a character to the stream.
Writes a character to the stream.
*/
*/
BasicWriter
&
operator
<<
(
char
value
)
{
BasicWriter
&
operator
<<
(
char
value
)
{
buffer_
.
push_back
(
value
);
buffer_
.
push_back
(
value
);
return
*
this
;
return
*
this
;
}
}
BasicWriter
&
operator
<<
(
BasicWriter
&
operator
<<
(
typename
internal
::
WCharHelper
<
wchar_t
,
Char
>::
Supported
value
)
{
typename
internal
::
WCharHelper
<
wchar_t
,
Char
>::
Supported
value
)
{
buffer_
.
push_back
(
value
);
buffer_
.
push_back
(
value
);
return
*
this
;
return
*
this
;
}
}
...
@@ -2569,56 +2839,66 @@ public:
...
@@ -2569,56 +2839,66 @@ public:
Writes *value* to the stream.
Writes *value* to the stream.
\endrst
\endrst
*/
*/
BasicWriter
&
operator
<<
(
fmt
::
BasicStringRef
<
Char
>
value
)
{
BasicWriter
&
operator
<<
(
fmt
::
BasicStringRef
<
Char
>
value
)
{
const
Char
*
str
=
value
.
data
();
const
Char
*
str
=
value
.
data
();
buffer_
.
append
(
str
,
str
+
value
.
size
());
buffer_
.
append
(
str
,
str
+
value
.
size
());
return
*
this
;
return
*
this
;
}
}
BasicWriter
&
operator
<<
(
BasicWriter
&
operator
<<
(
typename
internal
::
WCharHelper
<
StringRef
,
Char
>::
Supported
value
)
{
typename
internal
::
WCharHelper
<
StringRef
,
Char
>::
Supported
value
)
{
const
char
*
str
=
value
.
data
();
const
char
*
str
=
value
.
data
();
buffer_
.
append
(
str
,
str
+
value
.
size
());
buffer_
.
append
(
str
,
str
+
value
.
size
());
return
*
this
;
return
*
this
;
}
}
template
<
typename
T
,
typename
Spec
,
typename
FillChar
>
template
<
typename
T
,
typename
Spec
,
typename
FillChar
>
BasicWriter
&
operator
<<
(
IntFormatSpec
<
T
,
Spec
,
FillChar
>
spec
)
{
BasicWriter
&
operator
<<
(
IntFormatSpec
<
T
,
Spec
,
FillChar
>
spec
)
{
internal
::
CharTraits
<
Char
>::
convert
(
FillChar
());
internal
::
CharTraits
<
Char
>::
convert
(
FillChar
());
write_int
(
spec
.
value
(),
spec
);
write_int
(
spec
.
value
(),
spec
);
return
*
this
;
return
*
this
;
}
}
template
<
typename
StrChar
>
template
<
typename
StrChar
>
BasicWriter
&
operator
<<
(
const
StrFormatSpec
<
StrChar
>
&
spec
)
{
BasicWriter
&
operator
<<
(
const
StrFormatSpec
<
StrChar
>
&
spec
)
{
const
StrChar
*
s
=
spec
.
str
();
const
StrChar
*
s
=
spec
.
str
();
write_str
(
s
,
std
::
char_traits
<
Char
>::
length
(
s
),
spec
);
write_str
(
s
,
std
::
char_traits
<
Char
>::
length
(
s
),
spec
);
return
*
this
;
return
*
this
;
}
}
void
clear
()
FMT_NOEXCEPT
{
buffer_
.
clear
();
}
void
clear
()
FMT_NOEXCEPT
{
buffer_
.
clear
();
}
};
};
template
<
typename
Char
>
template
<
typename
Char
>
template
<
typename
StrChar
>
template
<
typename
StrChar
>
typename
BasicWriter
<
Char
>::
CharPtr
BasicWriter
<
Char
>::
write_str
(
typename
BasicWriter
<
Char
>::
CharPtr
BasicWriter
<
Char
>::
write_str
(
const
StrChar
*
s
,
std
::
size_t
size
,
const
AlignSpec
&
spec
)
{
const
StrChar
*
s
,
std
::
size_t
size
,
const
AlignSpec
&
spec
)
{
CharPtr
out
=
CharPtr
();
CharPtr
out
=
CharPtr
();
if
(
spec
.
width
()
>
size
)
{
if
(
spec
.
width
()
>
size
)
{
out
=
grow_buffer
(
spec
.
width
());
out
=
grow_buffer
(
spec
.
width
());
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec
.
fill
());
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec
.
fill
());
if
(
spec
.
align
()
==
ALIGN_RIGHT
)
{
if
(
spec
.
align
()
==
ALIGN_RIGHT
)
{
std
::
uninitialized_fill_n
(
out
,
spec
.
width
()
-
size
,
fill
);
std
::
uninitialized_fill_n
(
out
,
spec
.
width
()
-
size
,
fill
);
out
+=
spec
.
width
()
-
size
;
out
+=
spec
.
width
()
-
size
;
}
}
else
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
else
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
out
=
fill_padding
(
out
,
spec
.
width
(),
size
,
fill
);
out
=
fill_padding
(
out
,
spec
.
width
(),
size
,
fill
);
}
}
else
{
else
{
std
::
uninitialized_fill_n
(
out
+
size
,
spec
.
width
()
-
size
,
fill
);
std
::
uninitialized_fill_n
(
out
+
size
,
spec
.
width
()
-
size
,
fill
);
}
}
}
}
else
{
else
{
out
=
grow_buffer
(
size
);
out
=
grow_buffer
(
size
);
}
}
std
::
uninitialized_copy
(
s
,
s
+
size
,
out
);
std
::
uninitialized_copy
(
s
,
s
+
size
,
out
);
...
@@ -2628,15 +2908,18 @@ typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(
...
@@ -2628,15 +2908,18 @@ typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(
template
<
typename
Char
>
template
<
typename
Char
>
template
<
typename
StrChar
>
template
<
typename
StrChar
>
void
BasicWriter
<
Char
>::
write_str
(
void
BasicWriter
<
Char
>::
write_str
(
const
internal
::
Arg
::
StringValue
<
StrChar
>
&
s
,
const
FormatSpec
&
spec
)
{
const
internal
::
Arg
::
StringValue
<
StrChar
>
&
s
,
const
FormatSpec
&
spec
)
{
// Check if StrChar is convertible to Char.
// Check if StrChar is convertible to Char.
internal
::
CharTraits
<
Char
>::
convert
(
StrChar
());
internal
::
CharTraits
<
Char
>::
convert
(
StrChar
());
if
(
spec
.
type_
&&
spec
.
type_
!=
's'
)
if
(
spec
.
type_
&&
spec
.
type_
!=
's'
)
internal
::
report_unknown_type
(
spec
.
type_
,
"string"
);
internal
::
report_unknown_type
(
spec
.
type_
,
"string"
);
const
StrChar
*
str_value
=
s
.
value
;
const
StrChar
*
str_value
=
s
.
value
;
std
::
size_t
str_size
=
s
.
size
;
std
::
size_t
str_size
=
s
.
size
;
if
(
str_size
==
0
)
{
if
(
str_size
==
0
)
if
(
!
str_value
)
{
{
if
(
!
str_value
)
{
FMT_THROW
(
FormatError
(
"string pointer is null"
));
FMT_THROW
(
FormatError
(
"string pointer is null"
));
return
;
return
;
}
}
...
@@ -2651,7 +2934,8 @@ template <typename Char>
...
@@ -2651,7 +2934,8 @@ template <typename Char>
typename
BasicWriter
<
Char
>::
CharPtr
typename
BasicWriter
<
Char
>::
CharPtr
BasicWriter
<
Char
>::
fill_padding
(
BasicWriter
<
Char
>::
fill_padding
(
CharPtr
buffer
,
unsigned
total_size
,
CharPtr
buffer
,
unsigned
total_size
,
std
::
size_t
content_size
,
wchar_t
fill
)
{
std
::
size_t
content_size
,
wchar_t
fill
)
{
std
::
size_t
padding
=
total_size
-
content_size
;
std
::
size_t
padding
=
total_size
-
content_size
;
std
::
size_t
left_padding
=
padding
/
2
;
std
::
size_t
left_padding
=
padding
/
2
;
Char
fill_char
=
internal
::
CharTraits
<
Char
>::
cast
(
fill
);
Char
fill_char
=
internal
::
CharTraits
<
Char
>::
cast
(
fill
);
...
@@ -2668,11 +2952,13 @@ template <typename Spec>
...
@@ -2668,11 +2952,13 @@ template <typename Spec>
typename
BasicWriter
<
Char
>::
CharPtr
typename
BasicWriter
<
Char
>::
CharPtr
BasicWriter
<
Char
>::
prepare_int_buffer
(
BasicWriter
<
Char
>::
prepare_int_buffer
(
unsigned
num_digits
,
const
Spec
&
spec
,
unsigned
num_digits
,
const
Spec
&
spec
,
const
char
*
prefix
,
unsigned
prefix_size
)
{
const
char
*
prefix
,
unsigned
prefix_size
)
{
unsigned
width
=
spec
.
width
();
unsigned
width
=
spec
.
width
();
Alignment
align
=
spec
.
align
();
Alignment
align
=
spec
.
align
();
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec
.
fill
());
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec
.
fill
());
if
(
spec
.
precision
()
>
static_cast
<
int
>
(
num_digits
))
{
if
(
spec
.
precision
()
>
static_cast
<
int
>
(
num_digits
))
{
// Octal prefix '0' is counted as a digit, so ignore it if precision
// Octal prefix '0' is counted as a digit, so ignore it if precision
// is specified.
// is specified.
if
(
prefix_size
>
0
&&
prefix
[
prefix_size
-
1
]
==
'0'
)
if
(
prefix_size
>
0
&&
prefix
[
prefix_size
-
1
]
==
'0'
)
...
@@ -2683,44 +2969,53 @@ BasicWriter<Char>::prepare_int_buffer(
...
@@ -2683,44 +2969,53 @@ BasicWriter<Char>::prepare_int_buffer(
return
prepare_int_buffer
(
num_digits
,
subspec
,
prefix
,
prefix_size
);
return
prepare_int_buffer
(
num_digits
,
subspec
,
prefix
,
prefix_size
);
buffer_
.
reserve
(
width
);
buffer_
.
reserve
(
width
);
unsigned
fill_size
=
width
-
number_size
;
unsigned
fill_size
=
width
-
number_size
;
if
(
align
!=
ALIGN_LEFT
)
{
if
(
align
!=
ALIGN_LEFT
)
{
CharPtr
p
=
grow_buffer
(
fill_size
);
CharPtr
p
=
grow_buffer
(
fill_size
);
std
::
uninitialized_fill
(
p
,
p
+
fill_size
,
fill
);
std
::
uninitialized_fill
(
p
,
p
+
fill_size
,
fill
);
}
}
CharPtr
result
=
prepare_int_buffer
(
CharPtr
result
=
prepare_int_buffer
(
num_digits
,
subspec
,
prefix
,
prefix_size
);
num_digits
,
subspec
,
prefix
,
prefix_size
);
if
(
align
==
ALIGN_LEFT
)
{
if
(
align
==
ALIGN_LEFT
)
{
CharPtr
p
=
grow_buffer
(
fill_size
);
CharPtr
p
=
grow_buffer
(
fill_size
);
std
::
uninitialized_fill
(
p
,
p
+
fill_size
,
fill
);
std
::
uninitialized_fill
(
p
,
p
+
fill_size
,
fill
);
}
}
return
result
;
return
result
;
}
}
unsigned
size
=
prefix_size
+
num_digits
;
unsigned
size
=
prefix_size
+
num_digits
;
if
(
width
<=
size
)
{
if
(
width
<=
size
)
{
CharPtr
p
=
grow_buffer
(
size
);
CharPtr
p
=
grow_buffer
(
size
);
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
p
);
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
p
);
return
p
+
size
-
1
;
return
p
+
size
-
1
;
}
}
CharPtr
p
=
grow_buffer
(
width
);
CharPtr
p
=
grow_buffer
(
width
);
CharPtr
end
=
p
+
width
;
CharPtr
end
=
p
+
width
;
if
(
align
==
ALIGN_LEFT
)
{
if
(
align
==
ALIGN_LEFT
)
{
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
p
);
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
p
);
p
+=
size
;
p
+=
size
;
std
::
uninitialized_fill
(
p
,
end
,
fill
);
std
::
uninitialized_fill
(
p
,
end
,
fill
);
}
}
else
if
(
align
==
ALIGN_CENTER
)
{
else
if
(
align
==
ALIGN_CENTER
)
{
p
=
fill_padding
(
p
,
width
,
size
,
fill
);
p
=
fill_padding
(
p
,
width
,
size
,
fill
);
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
p
);
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
p
);
p
+=
size
;
p
+=
size
;
}
}
else
{
else
if
(
align
==
ALIGN_NUMERIC
)
{
{
if
(
prefix_size
!=
0
)
{
if
(
align
==
ALIGN_NUMERIC
)
{
if
(
prefix_size
!=
0
)
{
p
=
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
p
);
p
=
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
p
);
size
-=
prefix_size
;
size
-=
prefix_size
;
}
}
}
}
else
{
else
{
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
end
-
size
);
std
::
uninitialized_copy
(
prefix
,
prefix
+
prefix_size
,
end
-
size
);
}
}
std
::
uninitialized_fill
(
p
,
end
-
size
,
fill
);
std
::
uninitialized_fill
(
p
,
end
-
size
,
fill
);
...
@@ -2731,23 +3026,28 @@ BasicWriter<Char>::prepare_int_buffer(
...
@@ -2731,23 +3026,28 @@ BasicWriter<Char>::prepare_int_buffer(
template
<
typename
Char
>
template
<
typename
Char
>
template
<
typename
T
,
typename
Spec
>
template
<
typename
T
,
typename
Spec
>
void
BasicWriter
<
Char
>::
write_int
(
T
value
,
Spec
spec
)
{
void
BasicWriter
<
Char
>::
write_int
(
T
value
,
Spec
spec
)
{
unsigned
prefix_size
=
0
;
unsigned
prefix_size
=
0
;
typedef
typename
internal
::
IntTraits
<
T
>::
MainType
UnsignedType
;
typedef
typename
internal
::
IntTraits
<
T
>::
MainType
UnsignedType
;
UnsignedType
abs_value
=
value
;
UnsignedType
abs_value
=
value
;
char
prefix
[
4
]
=
""
;
char
prefix
[
4
]
=
""
;
if
(
internal
::
is_negative
(
value
))
{
if
(
internal
::
is_negative
(
value
))
{
prefix
[
0
]
=
'-'
;
prefix
[
0
]
=
'-'
;
++
prefix_size
;
++
prefix_size
;
abs_value
=
0
-
abs_value
;
abs_value
=
0
-
abs_value
;
}
}
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
prefix
[
0
]
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
prefix
[
0
]
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
++
prefix_size
;
++
prefix_size
;
}
}
switch
(
spec
.
type
())
{
switch
(
spec
.
type
())
{
case
0
:
case
0
:
case
'd'
:
{
case
'd'
:
{
unsigned
num_digits
=
internal
::
count_digits
(
abs_value
);
unsigned
num_digits
=
internal
::
count_digits
(
abs_value
);
CharPtr
p
=
prepare_int_buffer
(
CharPtr
p
=
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
)
+
1
-
num_digits
;
num_digits
,
spec
,
prefix
,
prefix_size
)
+
1
-
num_digits
;
...
@@ -2755,57 +3055,74 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
...
@@ -2755,57 +3055,74 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
break
;
break
;
}
}
case
'x'
:
case
'x'
:
case
'X'
:
{
case
'X'
:
{
UnsignedType
n
=
abs_value
;
UnsignedType
n
=
abs_value
;
if
(
spec
.
flag
(
HASH_FLAG
))
{
if
(
spec
.
flag
(
HASH_FLAG
))
{
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
spec
.
type
();
prefix
[
prefix_size
++
]
=
spec
.
type
();
}
}
unsigned
num_digits
=
0
;
unsigned
num_digits
=
0
;
do
{
do
{
++
num_digits
;
++
num_digits
;
}
while
((
n
>>=
4
)
!=
0
);
}
while
((
n
>>=
4
)
!=
0
);
Char
*
p
=
get
(
prepare_int_buffer
(
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
num_digits
,
spec
,
prefix
,
prefix_size
));
n
=
abs_value
;
n
=
abs_value
;
const
char
*
digits
=
spec
.
type
()
==
'x'
?
const
char
*
digits
=
spec
.
type
()
==
'x'
?
"0123456789abcdef"
:
"0123456789ABCDEF"
;
"0123456789abcdef"
:
"0123456789ABCDEF"
;
do
{
do
{
*
p
--
=
digits
[
n
&
0xf
];
*
p
--
=
digits
[
n
&
0xf
];
}
while
((
n
>>=
4
)
!=
0
);
}
while
((
n
>>=
4
)
!=
0
);
break
;
break
;
}
}
case
'b'
:
case
'b'
:
case
'B'
:
{
case
'B'
:
{
UnsignedType
n
=
abs_value
;
UnsignedType
n
=
abs_value
;
if
(
spec
.
flag
(
HASH_FLAG
))
{
if
(
spec
.
flag
(
HASH_FLAG
))
{
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
spec
.
type
();
prefix
[
prefix_size
++
]
=
spec
.
type
();
}
}
unsigned
num_digits
=
0
;
unsigned
num_digits
=
0
;
do
{
do
{
++
num_digits
;
++
num_digits
;
}
while
((
n
>>=
1
)
!=
0
);
}
while
((
n
>>=
1
)
!=
0
);
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
n
=
abs_value
;
n
=
abs_value
;
do
{
do
{
*
p
--
=
static_cast
<
Char
>
(
'0'
+
(
n
&
1
));
*
p
--
=
static_cast
<
Char
>
(
'0'
+
(
n
&
1
));
}
while
((
n
>>=
1
)
!=
0
);
}
while
((
n
>>=
1
)
!=
0
);
break
;
break
;
}
}
case
'o'
:
{
case
'o'
:
{
UnsignedType
n
=
abs_value
;
UnsignedType
n
=
abs_value
;
if
(
spec
.
flag
(
HASH_FLAG
))
if
(
spec
.
flag
(
HASH_FLAG
))
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
'0'
;
unsigned
num_digits
=
0
;
unsigned
num_digits
=
0
;
do
{
do
{
++
num_digits
;
++
num_digits
;
}
while
((
n
>>=
3
)
!=
0
);
}
while
((
n
>>=
3
)
!=
0
);
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
n
=
abs_value
;
n
=
abs_value
;
do
{
do
{
*
p
--
=
static_cast
<
Char
>
(
'0'
+
(
n
&
7
));
*
p
--
=
static_cast
<
Char
>
(
'0'
+
(
n
&
7
));
}
while
((
n
>>=
3
)
!=
0
);
}
while
((
n
>>=
3
)
!=
0
);
break
;
break
;
}
}
default
:
default
:
...
@@ -2818,11 +3135,13 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
...
@@ -2818,11 +3135,13 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
template
<
typename
Char
>
template
<
typename
Char
>
template
<
typename
T
>
template
<
typename
T
>
void
BasicWriter
<
Char
>::
write_double
(
void
BasicWriter
<
Char
>::
write_double
(
T
value
,
const
FormatSpec
&
spec
)
{
T
value
,
const
FormatSpec
&
spec
)
{
// Check type.
// Check type.
char
type
=
spec
.
type
();
char
type
=
spec
.
type
();
bool
upper
=
false
;
bool
upper
=
false
;
switch
(
type
)
{
switch
(
type
)
{
case
0
:
case
0
:
type
=
'g'
;
type
=
'g'
;
break
;
break
;
...
@@ -2850,20 +3169,24 @@ void BasicWriter<Char>::write_double(
...
@@ -2850,20 +3169,24 @@ void BasicWriter<Char>::write_double(
char
sign
=
0
;
char
sign
=
0
;
// Use isnegative instead of value < 0 because the latter is always
// Use isnegative instead of value < 0 because the latter is always
// false for NaN.
// false for NaN.
if
(
internal
::
FPUtil
::
isnegative
(
static_cast
<
double
>
(
value
)))
{
if
(
internal
::
FPUtil
::
isnegative
(
static_cast
<
double
>
(
value
)))
{
sign
=
'-'
;
sign
=
'-'
;
value
=
-
value
;
value
=
-
value
;
}
}
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
sign
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
sign
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
}
}
if
(
internal
::
FPUtil
::
isnotanumber
(
value
))
{
if
(
internal
::
FPUtil
::
isnotanumber
(
value
))
{
// Format NaN ourselves because sprintf's output is not consistent
// Format NaN ourselves because sprintf's output is not consistent
// across platforms.
// across platforms.
std
::
size_t
nan_size
=
4
;
std
::
size_t
nan_size
=
4
;
const
char
*
nan
=
upper
?
" NAN"
:
" nan"
;
const
char
*
nan
=
upper
?
" NAN"
:
" nan"
;
if
(
!
sign
)
{
if
(
!
sign
)
{
--
nan_size
;
--
nan_size
;
++
nan
;
++
nan
;
}
}
...
@@ -2873,12 +3196,14 @@ void BasicWriter<Char>::write_double(
...
@@ -2873,12 +3196,14 @@ void BasicWriter<Char>::write_double(
return
;
return
;
}
}
if
(
internal
::
FPUtil
::
isinfinity
(
value
))
{
if
(
internal
::
FPUtil
::
isinfinity
(
value
))
{
// Format infinity ourselves because sprintf's output is not consistent
// Format infinity ourselves because sprintf's output is not consistent
// across platforms.
// across platforms.
std
::
size_t
inf_size
=
4
;
std
::
size_t
inf_size
=
4
;
const
char
*
inf
=
upper
?
" INF"
:
" inf"
;
const
char
*
inf
=
upper
?
" INF"
:
" inf"
;
if
(
!
sign
)
{
if
(
!
sign
)
{
--
inf_size
;
--
inf_size
;
++
inf
;
++
inf
;
}
}
...
@@ -2890,7 +3215,8 @@ void BasicWriter<Char>::write_double(
...
@@ -2890,7 +3215,8 @@ void BasicWriter<Char>::write_double(
std
::
size_t
offset
=
buffer_
.
size
();
std
::
size_t
offset
=
buffer_
.
size
();
unsigned
width
=
spec
.
width
();
unsigned
width
=
spec
.
width
();
if
(
sign
)
{
if
(
sign
)
{
buffer_
.
reserve
(
buffer_
.
size
()
+
(
width
>
1u
?
width
:
1u
));
buffer_
.
reserve
(
buffer_
.
size
()
+
(
width
>
1u
?
width
:
1u
));
if
(
width
>
0
)
if
(
width
>
0
)
--
width
;
--
width
;
...
@@ -2905,16 +3231,19 @@ void BasicWriter<Char>::write_double(
...
@@ -2905,16 +3231,19 @@ void BasicWriter<Char>::write_double(
unsigned
width_for_sprintf
=
width
;
unsigned
width_for_sprintf
=
width
;
if
(
spec
.
flag
(
HASH_FLAG
))
if
(
spec
.
flag
(
HASH_FLAG
))
*
format_ptr
++
=
'#'
;
*
format_ptr
++
=
'#'
;
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
width_for_sprintf
=
0
;
width_for_sprintf
=
0
;
}
}
else
{
else
{
if
(
spec
.
align
()
==
ALIGN_LEFT
)
if
(
spec
.
align
()
==
ALIGN_LEFT
)
*
format_ptr
++
=
'-'
;
*
format_ptr
++
=
'-'
;
if
(
width
!=
0
)
if
(
width
!=
0
)
*
format_ptr
++
=
'*'
;
*
format_ptr
++
=
'*'
;
}
}
if
(
spec
.
precision
()
>=
0
)
{
if
(
spec
.
precision
()
>=
0
)
{
*
format_ptr
++
=
'.'
;
*
format_ptr
++
=
'.'
;
*
format_ptr
++
=
'*'
;
*
format_ptr
++
=
'*'
;
}
}
...
@@ -2925,13 +3254,15 @@ void BasicWriter<Char>::write_double(
...
@@ -2925,13 +3254,15 @@ void BasicWriter<Char>::write_double(
// Format using snprintf.
// Format using snprintf.
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec
.
fill
());
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec
.
fill
());
for
(;;)
{
for
(;;)
{
std
::
size_t
buffer_size
=
buffer_
.
capacity
()
-
offset
;
std
::
size_t
buffer_size
=
buffer_
.
capacity
()
-
offset
;
#ifdef _MSC_VER
#ifdef _MSC_VER
// MSVC's vsnprintf_s doesn't work with zero size, so reserve
// 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.
// space for at least one extra character to make the size non-zero.
// Note that the buffer's capacity will increase by more than 1.
// Note that the buffer's capacity will increase by more than 1.
if
(
buffer_size
==
0
)
{
if
(
buffer_size
==
0
)
{
buffer_
.
reserve
(
offset
+
1
);
buffer_
.
reserve
(
offset
+
1
);
buffer_size
=
buffer_
.
capacity
()
-
offset
;
buffer_size
=
buffer_
.
capacity
()
-
offset
;
}
}
...
@@ -2939,27 +3270,33 @@ void BasicWriter<Char>::write_double(
...
@@ -2939,27 +3270,33 @@ void BasicWriter<Char>::write_double(
Char
*
start
=
&
buffer_
[
offset
];
Char
*
start
=
&
buffer_
[
offset
];
int
n
=
internal
::
CharTraits
<
Char
>::
format_float
(
int
n
=
internal
::
CharTraits
<
Char
>::
format_float
(
start
,
buffer_size
,
format
,
width_for_sprintf
,
spec
.
precision
(),
value
);
start
,
buffer_size
,
format
,
width_for_sprintf
,
spec
.
precision
(),
value
);
if
(
n
>=
0
&&
offset
+
n
<
buffer_
.
capacity
())
{
if
(
n
>=
0
&&
offset
+
n
<
buffer_
.
capacity
())
if
(
sign
)
{
{
if
(
sign
)
{
if
((
spec
.
align
()
!=
ALIGN_RIGHT
&&
spec
.
align
()
!=
ALIGN_DEFAULT
)
||
if
((
spec
.
align
()
!=
ALIGN_RIGHT
&&
spec
.
align
()
!=
ALIGN_DEFAULT
)
||
*
start
!=
' '
)
{
*
start
!=
' '
)
{
*
(
start
-
1
)
=
sign
;
*
(
start
-
1
)
=
sign
;
sign
=
0
;
sign
=
0
;
}
}
else
{
else
{
*
(
start
-
1
)
=
fill
;
*
(
start
-
1
)
=
fill
;
}
}
++
n
;
++
n
;
}
}
if
(
spec
.
align
()
==
ALIGN_CENTER
&&
if
(
spec
.
align
()
==
ALIGN_CENTER
&&
spec
.
width
()
>
static_cast
<
unsigned
>
(
n
))
{
spec
.
width
()
>
static_cast
<
unsigned
>
(
n
))
{
width
=
spec
.
width
();
width
=
spec
.
width
();
CharPtr
p
=
grow_buffer
(
width
);
CharPtr
p
=
grow_buffer
(
width
);
std
::
memmove
(
get
(
p
)
+
(
width
-
n
)
/
2
,
get
(
p
),
n
*
sizeof
(
Char
));
std
::
memmove
(
get
(
p
)
+
(
width
-
n
)
/
2
,
get
(
p
),
n
*
sizeof
(
Char
));
fill_padding
(
p
,
spec
.
width
(),
n
,
fill
);
fill_padding
(
p
,
spec
.
width
(),
n
,
fill
);
return
;
return
;
}
}
if
(
spec
.
fill
()
!=
' '
||
sign
)
{
if
(
spec
.
fill
()
!=
' '
||
sign
)
{
while
(
*
start
==
' '
)
while
(
*
start
==
' '
)
*
start
++
=
fill
;
*
start
++
=
fill
;
if
(
sign
)
if
(
sign
)
...
@@ -3009,7 +3346,8 @@ accessed as a C string with ``out.c_str()``.
...
@@ -3009,7 +3346,8 @@ accessed as a C string with ``out.c_str()``.
\endrst
\endrst
*/
*/
template
<
typename
Char
,
typename
Allocator
=
std
::
allocator
<
Char
>
>
template
<
typename
Char
,
typename
Allocator
=
std
::
allocator
<
Char
>
>
class
BasicMemoryWriter
:
public
BasicWriter
<
Char
>
{
class
BasicMemoryWriter
:
public
BasicWriter
<
Char
>
{
private
:
private
:
internal
::
MemoryBuffer
<
Char
,
internal
::
INLINE_BUFFER_SIZE
,
Allocator
>
buffer_
;
internal
::
MemoryBuffer
<
Char
,
internal
::
INLINE_BUFFER_SIZE
,
Allocator
>
buffer_
;
...
@@ -3025,7 +3363,8 @@ public:
...
@@ -3025,7 +3363,8 @@ public:
\endrst
\endrst
*/
*/
BasicMemoryWriter
(
BasicMemoryWriter
&&
other
)
BasicMemoryWriter
(
BasicMemoryWriter
&&
other
)
:
BasicWriter
<
Char
>
(
buffer_
),
buffer_
(
std
::
move
(
other
.
buffer_
))
{
:
BasicWriter
<
Char
>
(
buffer_
),
buffer_
(
std
::
move
(
other
.
buffer_
))
{
}
}
/**
/**
...
@@ -3033,7 +3372,8 @@ public:
...
@@ -3033,7 +3372,8 @@ public:
Moves the content of the other ``BasicMemoryWriter`` object to this one.
Moves the content of the other ``BasicMemoryWriter`` object to this one.
\endrst
\endrst
*/
*/
BasicMemoryWriter
&
operator
=
(
BasicMemoryWriter
&&
other
)
{
BasicMemoryWriter
&
operator
=
(
BasicMemoryWriter
&&
other
)
{
buffer_
=
std
::
move
(
other
.
buffer_
);
buffer_
=
std
::
move
(
other
.
buffer_
);
return
*
this
;
return
*
this
;
}
}
...
@@ -3064,7 +3404,8 @@ You can use one of the following typedefs for common character types:
...
@@ -3064,7 +3404,8 @@ You can use one of the following typedefs for common character types:
\endrst
\endrst
*/
*/
template
<
typename
Char
>
template
<
typename
Char
>
class
BasicArrayWriter
:
public
BasicWriter
<
Char
>
{
class
BasicArrayWriter
:
public
BasicWriter
<
Char
>
{
private
:
private
:
internal
::
FixedBuffer
<
Char
>
buffer_
;
internal
::
FixedBuffer
<
Char
>
buffer_
;
...
@@ -3094,7 +3435,8 @@ typedef BasicArrayWriter<wchar_t> WArrayWriter;
...
@@ -3094,7 +3435,8 @@ typedef BasicArrayWriter<wchar_t> WArrayWriter;
// Formats a value.
// Formats a value.
template
<
typename
Char
,
typename
T
>
template
<
typename
Char
,
typename
T
>
void
format
(
BasicFormatter
<
Char
>
&
f
,
const
Char
*&
format_str
,
const
T
&
value
)
{
void
format
(
BasicFormatter
<
Char
>
&
f
,
const
Char
*&
format_str
,
const
T
&
value
)
{
internal
::
MemoryBuffer
<
Char
,
internal
::
INLINE_BUFFER_SIZE
>
buffer
;
internal
::
MemoryBuffer
<
Char
,
internal
::
INLINE_BUFFER_SIZE
>
buffer
;
internal
::
FormatBuf
<
Char
>
format_buf
(
buffer
);
internal
::
FormatBuf
<
Char
>
format_buf
(
buffer
);
...
@@ -3116,7 +3458,8 @@ FMT_API void report_system_error(int error_code,
...
@@ -3116,7 +3458,8 @@ FMT_API void report_system_error(int error_code,
#if FMT_USE_WINDOWS_H
#if FMT_USE_WINDOWS_H
/** A Windows error. */
/** A Windows error. */
class
WindowsError
:
public
SystemError
{
class
WindowsError
:
public
SystemError
{
private
:
private
:
FMT_API
void
init
(
int
error_code
,
CStringRef
format_str
,
ArgList
args
);
FMT_API
void
init
(
int
error_code
,
CStringRef
format_str
,
ArgList
args
);
...
@@ -3149,7 +3492,8 @@ public:
...
@@ -3149,7 +3492,8 @@ public:
}
}
\endrst
\endrst
*/
*/
WindowsError
(
int
error_code
,
CStringRef
message
)
{
WindowsError
(
int
error_code
,
CStringRef
message
)
{
init
(
error_code
,
message
,
ArgList
());
init
(
error_code
,
message
,
ArgList
());
}
}
FMT_VARIADIC_CTOR
(
WindowsError
,
init
,
int
,
CStringRef
)
FMT_VARIADIC_CTOR
(
WindowsError
,
init
,
int
,
CStringRef
)
...
@@ -3181,13 +3525,15 @@ Formats arguments and returns the result as a string.
...
@@ -3181,13 +3525,15 @@ Formats arguments and returns the result as a string.
std::string message = format("The answer is {}", 42);
std::string message = format("The answer is {}", 42);
\endrst
\endrst
*/
*/
inline
std
::
string
format
(
CStringRef
format_str
,
ArgList
args
)
{
inline
std
::
string
format
(
CStringRef
format_str
,
ArgList
args
)
{
MemoryWriter
w
;
MemoryWriter
w
;
w
.
write
(
format_str
,
args
);
w
.
write
(
format_str
,
args
);
return
w
.
str
();
return
w
.
str
();
}
}
inline
std
::
wstring
format
(
WCStringRef
format_str
,
ArgList
args
)
{
inline
std
::
wstring
format
(
WCStringRef
format_str
,
ArgList
args
)
{
WMemoryWriter
w
;
WMemoryWriter
w
;
w
.
write
(
format_str
,
args
);
w
.
write
(
format_str
,
args
);
return
w
.
str
();
return
w
.
str
();
...
@@ -3216,7 +3562,8 @@ print("Elapsed time: {0:.2f} seconds", 1.23);
...
@@ -3216,7 +3562,8 @@ print("Elapsed time: {0:.2f} seconds", 1.23);
FMT_API
void
print
(
CStringRef
format_str
,
ArgList
args
);
FMT_API
void
print
(
CStringRef
format_str
,
ArgList
args
);
template
<
typename
Char
>
template
<
typename
Char
>
void
printf
(
BasicWriter
<
Char
>
&
w
,
BasicCStringRef
<
Char
>
format
,
ArgList
args
)
{
void
printf
(
BasicWriter
<
Char
>
&
w
,
BasicCStringRef
<
Char
>
format
,
ArgList
args
)
{
internal
::
PrintfFormatter
<
Char
>
(
args
).
format
(
w
,
format
);
internal
::
PrintfFormatter
<
Char
>
(
args
).
format
(
w
,
format
);
}
}
...
@@ -3229,13 +3576,15 @@ Formats arguments and returns the result as a string.
...
@@ -3229,13 +3576,15 @@ Formats arguments and returns the result as a string.
std::string message = fmt::sprintf("The answer is %d", 42);
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
\endrst
*/
*/
inline
std
::
string
sprintf
(
CStringRef
format
,
ArgList
args
)
{
inline
std
::
string
sprintf
(
CStringRef
format
,
ArgList
args
)
{
MemoryWriter
w
;
MemoryWriter
w
;
printf
(
w
,
format
,
args
);
printf
(
w
,
format
,
args
);
return
w
.
str
();
return
w
.
str
();
}
}
inline
std
::
wstring
sprintf
(
WCStringRef
format
,
ArgList
args
)
{
inline
std
::
wstring
sprintf
(
WCStringRef
format
,
ArgList
args
)
{
WMemoryWriter
w
;
WMemoryWriter
w
;
printf
(
w
,
format
,
args
);
printf
(
w
,
format
,
args
);
return
w
.
str
();
return
w
.
str
();
...
@@ -3261,14 +3610,16 @@ Prints formatted data to ``stdout``.
...
@@ -3261,14 +3610,16 @@ Prints formatted data to ``stdout``.
fmt::printf("Elapsed time: %.2f seconds", 1.23);
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
\endrst
*/
*/
inline
int
printf
(
CStringRef
format
,
ArgList
args
)
{
inline
int
printf
(
CStringRef
format
,
ArgList
args
)
{
return
fprintf
(
stdout
,
format
,
args
);
return
fprintf
(
stdout
,
format
,
args
);
}
}
/**
/**
Fast integer formatter.
Fast integer formatter.
*/
*/
class
FormatInt
{
class
FormatInt
{
private
:
private
:
// Buffer should be large enough to hold all digits (digits10 + 1),
// Buffer should be large enough to hold all digits (digits10 + 1),
// a sign and a null character.
// a sign and a null character.
...
@@ -3277,9 +3628,11 @@ private:
...
@@ -3277,9 +3628,11 @@ private:
char
*
str_
;
char
*
str_
;
// Formats value in reverse and returns the number of digits.
// Formats value in reverse and returns the number of digits.
char
*
format_decimal
(
ULongLong
value
)
{
char
*
format_decimal
(
ULongLong
value
)
{
char
*
buffer_end
=
buffer_
+
BUFFER_SIZE
-
1
;
char
*
buffer_end
=
buffer_
+
BUFFER_SIZE
-
1
;
while
(
value
>=
100
)
{
while
(
value
>=
100
)
{
// Integer division is slow so do it for a group of two digits instead
// Integer division is slow so do it for a group of two digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
// "Three Optimization Tips for C++". See speed-test for a comparison.
...
@@ -3288,7 +3641,8 @@ private:
...
@@ -3288,7 +3641,8 @@ private:
*--
buffer_end
=
internal
::
Data
::
DIGITS
[
index
+
1
];
*--
buffer_end
=
internal
::
Data
::
DIGITS
[
index
+
1
];
*--
buffer_end
=
internal
::
Data
::
DIGITS
[
index
];
*--
buffer_end
=
internal
::
Data
::
DIGITS
[
index
];
}
}
if
(
value
<
10
)
{
if
(
value
<
10
)
{
*--
buffer_end
=
static_cast
<
char
>
(
'0'
+
value
);
*--
buffer_end
=
static_cast
<
char
>
(
'0'
+
value
);
return
buffer_end
;
return
buffer_end
;
}
}
...
@@ -3298,7 +3652,8 @@ private:
...
@@ -3298,7 +3652,8 @@ private:
return
buffer_end
;
return
buffer_end
;
}
}
void
FormatSigned
(
LongLong
value
)
{
void
FormatSigned
(
LongLong
value
)
{
ULongLong
abs_value
=
static_cast
<
ULongLong
>
(
value
);
ULongLong
abs_value
=
static_cast
<
ULongLong
>
(
value
);
bool
negative
=
value
<
0
;
bool
negative
=
value
<
0
;
if
(
negative
)
if
(
negative
)
...
@@ -3309,13 +3664,16 @@ private:
...
@@ -3309,13 +3664,16 @@ private:
}
}
public
:
public
:
explicit
FormatInt
(
int
value
)
{
explicit
FormatInt
(
int
value
)
{
FormatSigned
(
value
);
FormatSigned
(
value
);
}
}
explicit
FormatInt
(
long
value
)
{
explicit
FormatInt
(
long
value
)
{
FormatSigned
(
value
);
FormatSigned
(
value
);
}
}
explicit
FormatInt
(
LongLong
value
)
{
explicit
FormatInt
(
LongLong
value
)
{
FormatSigned
(
value
);
FormatSigned
(
value
);
}
}
explicit
FormatInt
(
unsigned
value
)
:
str_
(
format_decimal
(
value
))
{}
explicit
FormatInt
(
unsigned
value
)
:
str_
(
format_decimal
(
value
))
{}
...
@@ -3325,7 +3683,8 @@ public:
...
@@ -3325,7 +3683,8 @@ public:
/**
/**
Returns the number of characters written to the output buffer.
Returns the number of characters written to the output buffer.
*/
*/
std
::
size_t
size
()
const
{
std
::
size_t
size
()
const
{
return
buffer_
-
str_
+
BUFFER_SIZE
-
1
;
return
buffer_
-
str_
+
BUFFER_SIZE
-
1
;
}
}
...
@@ -3333,7 +3692,8 @@ public:
...
@@ -3333,7 +3692,8 @@ public:
Returns a pointer to the output buffer content. No terminating null
Returns a pointer to the output buffer content. No terminating null
character is appended.
character is appended.
*/
*/
const
char
*
data
()
const
{
const
char
*
data
()
const
{
return
str_
;
return
str_
;
}
}
...
@@ -3341,7 +3701,8 @@ public:
...
@@ -3341,7 +3701,8 @@ public:
Returns a pointer to the output buffer content with terminating null
Returns a pointer to the output buffer content with terminating null
character appended.
character appended.
*/
*/
const
char
*
c_str
()
const
{
const
char
*
c_str
()
const
{
buffer_
[
BUFFER_SIZE
-
1
]
=
'\0'
;
buffer_
[
BUFFER_SIZE
-
1
]
=
'\0'
;
return
str_
;
return
str_
;
}
}
...
@@ -3351,7 +3712,8 @@ public:
...
@@ -3351,7 +3712,8 @@ public:
Returns the content of the output buffer as an ``std::string``.
Returns the content of the output buffer as an ``std::string``.
\endrst
\endrst
*/
*/
std
::
string
str
()
const
{
std
::
string
str
()
const
{
return
std
::
string
(
str_
,
size
());
return
std
::
string
(
str_
,
size
());
}
}
};
};
...
@@ -3360,14 +3722,18 @@ public:
...
@@ -3360,14 +3722,18 @@ public:
// a pointer to the end of the formatted string. This function doesn't
// a pointer to the end of the formatted string. This function doesn't
// write a terminating null character.
// write a terminating null character.
template
<
typename
T
>
template
<
typename
T
>
inline
void
format_decimal
(
char
*&
buffer
,
T
value
)
{
inline
void
format_decimal
(
char
*&
buffer
,
T
value
)
{
typename
internal
::
IntTraits
<
T
>::
MainType
abs_value
=
value
;
typename
internal
::
IntTraits
<
T
>::
MainType
abs_value
=
value
;
if
(
internal
::
is_negative
(
value
))
{
if
(
internal
::
is_negative
(
value
))
{
*
buffer
++
=
'-'
;
*
buffer
++
=
'-'
;
abs_value
=
0
-
abs_value
;
abs_value
=
0
-
abs_value
;
}
}
if
(
abs_value
<
100
)
{
if
(
abs_value
<
100
)
if
(
abs_value
<
10
)
{
{
if
(
abs_value
<
10
)
{
*
buffer
++
=
static_cast
<
char
>
(
'0'
+
abs_value
);
*
buffer
++
=
static_cast
<
char
>
(
'0'
+
abs_value
);
return
;
return
;
}
}
...
@@ -3392,12 +3758,14 @@ print("Elapsed time: {s:.2f} seconds", arg("s", 1.23));
...
@@ -3392,12 +3758,14 @@ print("Elapsed time: {s:.2f} seconds", arg("s", 1.23));
\endrst
\endrst
*/
*/
template
<
typename
T
>
template
<
typename
T
>
inline
internal
::
NamedArg
<
char
>
arg
(
StringRef
name
,
const
T
&
arg
)
{
inline
internal
::
NamedArg
<
char
>
arg
(
StringRef
name
,
const
T
&
arg
)
{
return
internal
::
NamedArg
<
char
>
(
name
,
arg
);
return
internal
::
NamedArg
<
char
>
(
name
,
arg
);
}
}
template
<
typename
T
>
template
<
typename
T
>
inline
internal
::
NamedArg
<
wchar_t
>
arg
(
WStringRef
name
,
const
T
&
arg
)
{
inline
internal
::
NamedArg
<
wchar_t
>
arg
(
WStringRef
name
,
const
T
&
arg
)
{
return
internal
::
NamedArg
<
wchar_t
>
(
name
,
arg
);
return
internal
::
NamedArg
<
wchar_t
>
(
name
,
arg
);
}
}
...
@@ -3535,7 +3903,8 @@ print("point: ({x}, {y})", FMT_CAPTURE(x, y));
...
@@ -3535,7 +3903,8 @@ print("point: ({x}, {y})", FMT_CAPTURE(x, y));
#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__)
#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__)
namespace
fmt
{
namespace
fmt
{
FMT_VARIADIC
(
std
::
string
,
format
,
CStringRef
)
FMT_VARIADIC
(
std
::
string
,
format
,
CStringRef
)
FMT_VARIADIC_W
(
std
::
wstring
,
format
,
WCStringRef
)
FMT_VARIADIC_W
(
std
::
wstring
,
format
,
WCStringRef
)
FMT_VARIADIC
(
void
,
print
,
CStringRef
)
FMT_VARIADIC
(
void
,
print
,
CStringRef
)
...
@@ -3561,27 +3930,33 @@ FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
...
@@ -3561,27 +3930,33 @@ FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC
(
void
,
print
,
std
::
ostream
&
,
CStringRef
)
FMT_VARIADIC
(
void
,
print
,
std
::
ostream
&
,
CStringRef
)
#endif
#endif
namespace
internal
{
namespace
internal
{
template
<
typename
Char
>
template
<
typename
Char
>
inline
bool
is_name_start
(
Char
c
)
{
inline
bool
is_name_start
(
Char
c
)
{
return
(
'a'
<=
c
&&
c
<=
'z'
)
||
(
'A'
<=
c
&&
c
<=
'Z'
)
||
'_'
==
c
;
return
(
'a'
<=
c
&&
c
<=
'z'
)
||
(
'A'
<=
c
&&
c
<=
'Z'
)
||
'_'
==
c
;
}
}
// Parses an unsigned integer advancing s to the end of the parsed input.
// Parses an unsigned integer advancing s to the end of the parsed input.
// This function assumes that the first character of s is a digit.
// This function assumes that the first character of s is a digit.
template
<
typename
Char
>
template
<
typename
Char
>
int
parse_nonnegative_int
(
const
Char
*&
s
)
{
int
parse_nonnegative_int
(
const
Char
*&
s
)
{
assert
(
'0'
<=
*
s
&&
*
s
<=
'9'
);
assert
(
'0'
<=
*
s
&&
*
s
<=
'9'
);
unsigned
value
=
0
;
unsigned
value
=
0
;
do
{
do
{
unsigned
new_value
=
value
*
10
+
(
*
s
++
-
'0'
);
unsigned
new_value
=
value
*
10
+
(
*
s
++
-
'0'
);
// Check if value wrapped around.
// Check if value wrapped around.
if
(
new_value
<
value
)
{
if
(
new_value
<
value
)
{
value
=
(
std
::
numeric_limits
<
unsigned
>::
max
)();
value
=
(
std
::
numeric_limits
<
unsigned
>::
max
)();
break
;
break
;
}
}
value
=
new_value
;
value
=
new_value
;
}
while
(
'0'
<=
*
s
&&
*
s
<=
'9'
);
}
while
(
'0'
<=
*
s
&&
*
s
<=
'9'
);
// Convert to unsigned to prevent a warning.
// Convert to unsigned to prevent a warning.
unsigned
max_int
=
(
std
::
numeric_limits
<
int
>::
max
)();
unsigned
max_int
=
(
std
::
numeric_limits
<
int
>::
max
)();
if
(
value
>
max_int
)
if
(
value
>
max_int
)
...
@@ -3589,8 +3964,10 @@ int parse_nonnegative_int(const Char *&s) {
...
@@ -3589,8 +3964,10 @@ int parse_nonnegative_int(const Char *&s) {
return
value
;
return
value
;
}
}
inline
void
require_numeric_argument
(
const
Arg
&
arg
,
char
spec
)
{
inline
void
require_numeric_argument
(
const
Arg
&
arg
,
char
spec
)
if
(
arg
.
type
>
Arg
::
LAST_NUMERIC_TYPE
)
{
{
if
(
arg
.
type
>
Arg
::
LAST_NUMERIC_TYPE
)
{
std
::
string
message
=
std
::
string
message
=
fmt
::
format
(
"format specifier '{}' requires numeric argument"
,
spec
);
fmt
::
format
(
"format specifier '{}' requires numeric argument"
,
spec
);
FMT_THROW
(
fmt
::
FormatError
(
message
));
FMT_THROW
(
fmt
::
FormatError
(
message
));
...
@@ -3598,10 +3975,12 @@ inline void require_numeric_argument(const Arg &arg, char spec) {
...
@@ -3598,10 +3975,12 @@ inline void require_numeric_argument(const Arg &arg, char spec) {
}
}
template
<
typename
Char
>
template
<
typename
Char
>
void
check_sign
(
const
Char
*&
s
,
const
Arg
&
arg
)
{
void
check_sign
(
const
Char
*&
s
,
const
Arg
&
arg
)
{
char
sign
=
static_cast
<
char
>
(
*
s
);
char
sign
=
static_cast
<
char
>
(
*
s
);
require_numeric_argument
(
arg
,
sign
);
require_numeric_argument
(
arg
,
sign
);
if
(
arg
.
type
==
Arg
::
UINT
||
arg
.
type
==
Arg
::
ULONG_LONG
)
{
if
(
arg
.
type
==
Arg
::
UINT
||
arg
.
type
==
Arg
::
ULONG_LONG
)
{
FMT_THROW
(
FormatError
(
fmt
::
format
(
FMT_THROW
(
FormatError
(
fmt
::
format
(
"format specifier '{}' requires signed argument"
,
sign
)));
"format specifier '{}' requires signed argument"
,
sign
)));
}
}
...
@@ -3611,8 +3990,10 @@ void check_sign(const Char *&s, const Arg &arg) {
...
@@ -3611,8 +3990,10 @@ void check_sign(const Char *&s, const Arg &arg) {
template
<
typename
Char
>
template
<
typename
Char
>
inline
internal
::
Arg
BasicFormatter
<
Char
>::
get_arg
(
inline
internal
::
Arg
BasicFormatter
<
Char
>::
get_arg
(
BasicStringRef
<
Char
>
arg_name
,
const
char
*&
error
)
{
BasicStringRef
<
Char
>
arg_name
,
const
char
*&
error
)
if
(
check_no_auto_index
(
error
))
{
{
if
(
check_no_auto_index
(
error
))
{
map_
.
init
(
args
());
map_
.
init
(
args
());
const
internal
::
Arg
*
arg
=
map_
.
find
(
arg_name
);
const
internal
::
Arg
*
arg
=
map_
.
find
(
arg_name
);
if
(
arg
)
if
(
arg
)
...
@@ -3623,11 +4004,13 @@ inline internal::Arg BasicFormatter<Char>::get_arg(
...
@@ -3623,11 +4004,13 @@ inline internal::Arg BasicFormatter<Char>::get_arg(
}
}
template
<
typename
Char
>
template
<
typename
Char
>
inline
internal
::
Arg
BasicFormatter
<
Char
>::
parse_arg_index
(
const
Char
*&
s
)
{
inline
internal
::
Arg
BasicFormatter
<
Char
>::
parse_arg_index
(
const
Char
*&
s
)
{
const
char
*
error
=
0
;
const
char
*
error
=
0
;
internal
::
Arg
arg
=
*
s
<
'0'
||
*
s
>
'9'
?
internal
::
Arg
arg
=
*
s
<
'0'
||
*
s
>
'9'
?
next_arg
(
error
)
:
get_arg
(
internal
::
parse_nonnegative_int
(
s
),
error
);
next_arg
(
error
)
:
get_arg
(
internal
::
parse_nonnegative_int
(
s
),
error
);
if
(
error
)
{
if
(
error
)
{
FMT_THROW
(
FormatError
(
FMT_THROW
(
FormatError
(
*
s
!=
'}'
&&
*
s
!=
':'
?
"invalid format string"
:
error
));
*
s
!=
'}'
&&
*
s
!=
':'
?
"invalid format string"
:
error
));
}
}
...
@@ -3635,13 +4018,16 @@ inline internal::Arg BasicFormatter<Char>::parse_arg_index(const Char *&s) {
...
@@ -3635,13 +4018,16 @@ inline internal::Arg BasicFormatter<Char>::parse_arg_index(const Char *&s) {
}
}
template
<
typename
Char
>
template
<
typename
Char
>
inline
internal
::
Arg
BasicFormatter
<
Char
>::
parse_arg_name
(
const
Char
*&
s
)
{
inline
internal
::
Arg
BasicFormatter
<
Char
>::
parse_arg_name
(
const
Char
*&
s
)
{
assert
(
internal
::
is_name_start
(
*
s
));
assert
(
internal
::
is_name_start
(
*
s
));
const
Char
*
start
=
s
;
const
Char
*
start
=
s
;
Char
c
;
Char
c
;
do
{
do
{
c
=
*++
s
;
c
=
*++
s
;
}
while
(
internal
::
is_name_start
(
c
)
||
(
'0'
<=
c
&&
c
<=
'9'
));
}
while
(
internal
::
is_name_start
(
c
)
||
(
'0'
<=
c
&&
c
<=
'9'
));
const
char
*
error
=
0
;
const
char
*
error
=
0
;
internal
::
Arg
arg
=
get_arg
(
BasicStringRef
<
Char
>
(
start
,
s
-
start
),
error
);
internal
::
Arg
arg
=
get_arg
(
BasicStringRef
<
Char
>
(
start
,
s
-
start
),
error
);
if
(
error
)
if
(
error
)
...
@@ -3652,22 +4038,28 @@ inline internal::Arg BasicFormatter<Char>::parse_arg_name(const Char *&s) {
...
@@ -3652,22 +4038,28 @@ inline internal::Arg BasicFormatter<Char>::parse_arg_name(const Char *&s) {
// Should be after FormatSpec
// Should be after FormatSpec
template
<
typename
Char
>
template
<
typename
Char
>
const
Char
*
BasicFormatter
<
Char
>::
format
(
const
Char
*
BasicFormatter
<
Char
>::
format
(
const
Char
*&
format_str
,
const
internal
::
Arg
&
arg
)
{
const
Char
*&
format_str
,
const
internal
::
Arg
&
arg
)
{
using
internal
::
Arg
;
using
internal
::
Arg
;
const
Char
*
s
=
format_str
;
const
Char
*
s
=
format_str
;
FormatSpec
spec
;
FormatSpec
spec
;
if
(
*
s
==
':'
)
{
if
(
*
s
==
':'
)
if
(
arg
.
type
==
Arg
::
CUSTOM
)
{
{
if
(
arg
.
type
==
Arg
::
CUSTOM
)
{
arg
.
custom
.
format
(
this
,
arg
.
custom
.
value
,
&
s
);
arg
.
custom
.
format
(
this
,
arg
.
custom
.
value
,
&
s
);
return
s
;
return
s
;
}
}
++
s
;
++
s
;
// Parse fill and alignment.
// Parse fill and alignment.
if
(
Char
c
=
*
s
)
{
if
(
Char
c
=
*
s
)
{
const
Char
*
p
=
s
+
1
;
const
Char
*
p
=
s
+
1
;
spec
.
align_
=
ALIGN_DEFAULT
;
spec
.
align_
=
ALIGN_DEFAULT
;
do
{
do
switch
(
*
p
)
{
{
switch
(
*
p
)
{
case
'<'
:
case
'<'
:
spec
.
align_
=
ALIGN_LEFT
;
spec
.
align_
=
ALIGN_LEFT
;
break
;
break
;
...
@@ -3681,8 +4073,10 @@ const Char *BasicFormatter<Char>::format(
...
@@ -3681,8 +4073,10 @@ const Char *BasicFormatter<Char>::format(
spec
.
align_
=
ALIGN_CENTER
;
spec
.
align_
=
ALIGN_CENTER
;
break
;
break
;
}
}
if
(
spec
.
align_
!=
ALIGN_DEFAULT
)
{
if
(
spec
.
align_
!=
ALIGN_DEFAULT
)
if
(
p
!=
s
)
{
{
if
(
p
!=
s
)
{
if
(
c
==
'}'
)
break
;
if
(
c
==
'}'
)
break
;
if
(
c
==
'{'
)
if
(
c
==
'{'
)
FMT_THROW
(
FormatError
(
"invalid fill character '{'"
));
FMT_THROW
(
FormatError
(
"invalid fill character '{'"
));
...
@@ -3694,11 +4088,13 @@ const Char *BasicFormatter<Char>::format(
...
@@ -3694,11 +4088,13 @@ const Char *BasicFormatter<Char>::format(
require_numeric_argument
(
arg
,
'='
);
require_numeric_argument
(
arg
,
'='
);
break
;
break
;
}
}
}
while
(
--
p
>=
s
);
}
while
(
--
p
>=
s
);
}
}
// Parse sign.
// Parse sign.
switch
(
*
s
)
{
switch
(
*
s
)
{
case
'+'
:
case
'+'
:
check_sign
(
s
,
arg
);
check_sign
(
s
,
arg
);
spec
.
flags_
|=
SIGN_FLAG
|
PLUS_FLAG
;
spec
.
flags_
|=
SIGN_FLAG
|
PLUS_FLAG
;
...
@@ -3713,14 +4109,16 @@ const Char *BasicFormatter<Char>::format(
...
@@ -3713,14 +4109,16 @@ const Char *BasicFormatter<Char>::format(
break
;
break
;
}
}
if
(
*
s
==
'#'
)
{
if
(
*
s
==
'#'
)
{
require_numeric_argument
(
arg
,
'#'
);
require_numeric_argument
(
arg
,
'#'
);
spec
.
flags_
|=
HASH_FLAG
;
spec
.
flags_
|=
HASH_FLAG
;
++
s
;
++
s
;
}
}
// Parse zero flag.
// Parse zero flag.
if
(
*
s
==
'0'
)
{
if
(
*
s
==
'0'
)
{
require_numeric_argument
(
arg
,
'0'
);
require_numeric_argument
(
arg
,
'0'
);
spec
.
align_
=
ALIGN_NUMERIC
;
spec
.
align_
=
ALIGN_NUMERIC
;
spec
.
fill_
=
'0'
;
spec
.
fill_
=
'0'
;
...
@@ -3728,17 +4126,20 @@ const Char *BasicFormatter<Char>::format(
...
@@ -3728,17 +4126,20 @@ const Char *BasicFormatter<Char>::format(
}
}
// Parse width.
// Parse width.
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
spec
.
width_
=
internal
::
parse_nonnegative_int
(
s
);
spec
.
width_
=
internal
::
parse_nonnegative_int
(
s
);
}
}
else
if
(
*
s
==
'{'
)
{
else
if
(
*
s
==
'{'
)
{
++
s
;
++
s
;
Arg
width_arg
=
internal
::
is_name_start
(
*
s
)
?
Arg
width_arg
=
internal
::
is_name_start
(
*
s
)
?
parse_arg_name
(
s
)
:
parse_arg_index
(
s
);
parse_arg_name
(
s
)
:
parse_arg_index
(
s
);
if
(
*
s
++
!=
'}'
)
if
(
*
s
++
!=
'}'
)
FMT_THROW
(
FormatError
(
"invalid format string"
));
FMT_THROW
(
FormatError
(
"invalid format string"
));
ULongLong
value
=
0
;
ULongLong
value
=
0
;
switch
(
width_arg
.
type
)
{
switch
(
width_arg
.
type
)
{
case
Arg
:
:
INT
:
case
Arg
:
:
INT
:
if
(
width_arg
.
int_value
<
0
)
if
(
width_arg
.
int_value
<
0
)
FMT_THROW
(
FormatError
(
"negative width"
));
FMT_THROW
(
FormatError
(
"negative width"
));
...
@@ -3764,20 +4165,24 @@ const Char *BasicFormatter<Char>::format(
...
@@ -3764,20 +4165,24 @@ const Char *BasicFormatter<Char>::format(
}
}
// Parse precision.
// Parse precision.
if
(
*
s
==
'.'
)
{
if
(
*
s
==
'.'
)
{
++
s
;
++
s
;
spec
.
precision_
=
0
;
spec
.
precision_
=
0
;
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
spec
.
precision_
=
internal
::
parse_nonnegative_int
(
s
);
spec
.
precision_
=
internal
::
parse_nonnegative_int
(
s
);
}
}
else
if
(
*
s
==
'{'
)
{
else
if
(
*
s
==
'{'
)
{
++
s
;
++
s
;
Arg
precision_arg
=
internal
::
is_name_start
(
*
s
)
?
Arg
precision_arg
=
internal
::
is_name_start
(
*
s
)
?
parse_arg_name
(
s
)
:
parse_arg_index
(
s
);
parse_arg_name
(
s
)
:
parse_arg_index
(
s
);
if
(
*
s
++
!=
'}'
)
if
(
*
s
++
!=
'}'
)
FMT_THROW
(
FormatError
(
"invalid format string"
));
FMT_THROW
(
FormatError
(
"invalid format string"
));
ULongLong
value
=
0
;
ULongLong
value
=
0
;
switch
(
precision_arg
.
type
)
{
switch
(
precision_arg
.
type
)
{
case
Arg
:
:
INT
:
case
Arg
:
:
INT
:
if
(
precision_arg
.
int_value
<
0
)
if
(
precision_arg
.
int_value
<
0
)
FMT_THROW
(
FormatError
(
"negative precision"
));
FMT_THROW
(
FormatError
(
"negative precision"
));
...
@@ -3801,10 +4206,12 @@ const Char *BasicFormatter<Char>::format(
...
@@ -3801,10 +4206,12 @@ const Char *BasicFormatter<Char>::format(
FMT_THROW
(
FormatError
(
"number is too big"
));
FMT_THROW
(
FormatError
(
"number is too big"
));
spec
.
precision_
=
static_cast
<
int
>
(
value
);
spec
.
precision_
=
static_cast
<
int
>
(
value
);
}
}
else
{
else
{
FMT_THROW
(
FormatError
(
"missing precision specifier"
));
FMT_THROW
(
FormatError
(
"missing precision specifier"
));
}
}
if
(
arg
.
type
<=
Arg
::
LAST_INTEGER_TYPE
||
arg
.
type
==
Arg
::
POINTER
)
{
if
(
arg
.
type
<=
Arg
::
LAST_INTEGER_TYPE
||
arg
.
type
==
Arg
::
POINTER
)
{
FMT_THROW
(
FormatError
(
FMT_THROW
(
FormatError
(
fmt
::
format
(
"precision not allowed in {} format specifier"
,
fmt
::
format
(
"precision not allowed in {} format specifier"
,
arg
.
type
==
Arg
::
POINTER
?
"pointer"
:
"integer"
)));
arg
.
type
==
Arg
::
POINTER
?
"pointer"
:
"integer"
)));
...
@@ -3825,13 +4232,16 @@ const Char *BasicFormatter<Char>::format(
...
@@ -3825,13 +4232,16 @@ const Char *BasicFormatter<Char>::format(
}
}
template
<
typename
Char
>
template
<
typename
Char
>
void
BasicFormatter
<
Char
>::
format
(
BasicCStringRef
<
Char
>
format_str
)
{
void
BasicFormatter
<
Char
>::
format
(
BasicCStringRef
<
Char
>
format_str
)
{
const
Char
*
s
=
format_str
.
c_str
();
const
Char
*
s
=
format_str
.
c_str
();
const
Char
*
start
=
s
;
const
Char
*
start
=
s
;
while
(
*
s
)
{
while
(
*
s
)
{
Char
c
=
*
s
++
;
Char
c
=
*
s
++
;
if
(
c
!=
'{'
&&
c
!=
'}'
)
continue
;
if
(
c
!=
'{'
&&
c
!=
'}'
)
continue
;
if
(
*
s
==
c
)
{
if
(
*
s
==
c
)
{
write
(
writer_
,
start
,
s
);
write
(
writer_
,
start
,
s
);
start
=
++
s
;
start
=
++
s
;
continue
;
continue
;
...
@@ -3848,33 +4258,40 @@ void BasicFormatter<Char>::format(BasicCStringRef<Char> format_str) {
...
@@ -3848,33 +4258,40 @@ void BasicFormatter<Char>::format(BasicCStringRef<Char> format_str) {
}
// namespace fmt
}
// namespace fmt
#if FMT_USE_USER_DEFINED_LITERALS
#if FMT_USE_USER_DEFINED_LITERALS
namespace
fmt
{
namespace
fmt
namespace
internal
{
{
namespace
internal
{
template
<
typename
Char
>
template
<
typename
Char
>
struct
UdlFormat
{
struct
UdlFormat
{
const
Char
*
str
;
const
Char
*
str
;
template
<
typename
...
Args
>
template
<
typename
...
Args
>
auto
operator
()(
Args
&&
...
args
)
const
auto
operator
()(
Args
&&
...
args
)
const
->
decltype
(
format
(
str
,
std
::
forward
<
Args
>
(
args
)...))
{
->
decltype
(
format
(
str
,
std
::
forward
<
Args
>
(
args
)...))
{
return
format
(
str
,
std
::
forward
<
Args
>
(
args
)...);
return
format
(
str
,
std
::
forward
<
Args
>
(
args
)...);
}
}
};
};
template
<
typename
Char
>
template
<
typename
Char
>
struct
UdlArg
{
struct
UdlArg
{
const
Char
*
str
;
const
Char
*
str
;
template
<
typename
T
>
template
<
typename
T
>
NamedArg
<
Char
>
operator
=
(
T
&&
value
)
const
{
NamedArg
<
Char
>
operator
=
(
T
&&
value
)
const
return
{
str
,
std
::
forward
<
T
>
(
value
)
};
{
return
{
str
,
std
::
forward
<
T
>
(
value
)
};
}
}
};
};
}
// namespace internal
}
// namespace internal
inline
namespace
literals
{
inline
namespace
literals
{
/**
/**
\rst
\rst
...
@@ -3887,12 +4304,14 @@ std::string message = "The answer is {}"_format(42);
...
@@ -3887,12 +4304,14 @@ std::string message = "The answer is {}"_format(42);
\endrst
\endrst
*/
*/
inline
internal
::
UdlFormat
<
char
>
inline
internal
::
UdlFormat
<
char
>
operator
""
_format
(
const
char
*
s
,
std
::
size_t
)
{
operator
""
_format
(
const
char
*
s
,
std
::
size_t
)
return
{
s
};
{
return
{
s
};
}
}
inline
internal
::
UdlFormat
<
wchar_t
>
inline
internal
::
UdlFormat
<
wchar_t
>
operator
""
_format
(
const
wchar_t
*
s
,
std
::
size_t
)
{
operator
""
_format
(
const
wchar_t
*
s
,
std
::
size_t
)
return
{
s
};
{
return
{
s
};
}
}
/**
/**
...
@@ -3906,12 +4325,14 @@ print("Elapsed time: {s:.2f} seconds", "s"_a=1.23);
...
@@ -3906,12 +4325,14 @@ print("Elapsed time: {s:.2f} seconds", "s"_a=1.23);
\endrst
\endrst
*/
*/
inline
internal
::
UdlArg
<
char
>
inline
internal
::
UdlArg
<
char
>
operator
""
_a
(
const
char
*
s
,
std
::
size_t
)
{
operator
""
_a
(
const
char
*
s
,
std
::
size_t
)
return
{
s
};
{
return
{
s
};
}
}
inline
internal
::
UdlArg
<
wchar_t
>
inline
internal
::
UdlArg
<
wchar_t
>
operator
""
_a
(
const
wchar_t
*
s
,
std
::
size_t
)
{
operator
""
_a
(
const
wchar_t
*
s
,
std
::
size_t
)
return
{
s
};
{
return
{
s
};
}
}
}
// inline namespace literals
}
// inline namespace literals
...
...
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