Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
fmt
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
fmt
Commits
bc6c1c17
Commit
bc6c1c17
authored
Sep 04, 2013
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for wide strings.
parent
6d33ce9f
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
86 additions
and
41 deletions
+86
-41
README.rst
README.rst
+1
-0
format.h
format.h
+81
-41
format_test.cc
format_test.cc
+4
-0
No files found.
README.rst
View file @
bc6c1c17
...
@@ -34,6 +34,7 @@ Features
...
@@ -34,6 +34,7 @@ Features
for older compilers.
for older compilers.
* Clean warning-free codebase even on high warning levels
* Clean warning-free codebase even on high warning levels
(-Wall -Wextra -pedantic).
(-Wall -Wextra -pedantic).
* Support for wide strings.
See the `documentation <http://vitaut.github.com/format/>`__ for more details.
See the `documentation <http://vitaut.github.com/format/>`__ for more details.
...
...
format.h
View file @
bc6c1c17
...
@@ -105,6 +105,41 @@ inline int IsInf(double x) { return !_finite(x); }
...
@@ -105,6 +105,41 @@ inline int IsInf(double x) { return !_finite(x); }
#endif // _MSC_VER
#endif // _MSC_VER
template
<
typename
Char
>
struct
CharTraits
;
template
<
>
struct
CharTraits
<
char
>
{
template
<
typename
T
>
static
int
FormatFloat
(
char
*
buffer
,
std
::
size_t
size
,
const
char
*
format
,
unsigned
width
,
int
precision
,
T
value
)
{
if
(
width
==
0
)
{
return
precision
<
0
?
FMT_SNPRINTF
(
buffer
,
size
,
format
,
value
)
:
FMT_SNPRINTF
(
buffer
,
size
,
format
,
precision
,
value
);
}
return
precision
<
0
?
FMT_SNPRINTF
(
buffer
,
size
,
format
,
width
,
value
)
:
FMT_SNPRINTF
(
buffer
,
size
,
format
,
width
,
precision
,
value
);
}
};
template
<
>
struct
CharTraits
<
wchar_t
>
{
template
<
typename
T
>
static
int
FormatFloat
(
wchar_t
*
buffer
,
std
::
size_t
size
,
const
wchar_t
*
format
,
unsigned
width
,
int
precision
,
T
value
)
{
if
(
width
==
0
)
{
return
precision
<
0
?
swprintf
(
buffer
,
size
,
format
,
value
)
:
swprintf
(
buffer
,
size
,
format
,
precision
,
value
);
}
return
precision
<
0
?
swprintf
(
buffer
,
size
,
format
,
width
,
value
)
:
swprintf
(
buffer
,
size
,
format
,
width
,
precision
,
value
);
}
};
// A simple array for POD types with the first SIZE elements stored in
// A simple array for POD types with the first SIZE elements stored in
// the object itself. It supports a subset of std::vector's operations.
// the object itself. It supports a subset of std::vector's operations.
template
<
typename
T
,
std
::
size_t
SIZE
>
template
<
typename
T
,
std
::
size_t
SIZE
>
...
@@ -244,9 +279,10 @@ class FormatterProxy;
...
@@ -244,9 +279,10 @@ class FormatterProxy;
Format(Format("{{}}")) << 42;
Format(Format("{{}}")) << 42;
\endrst
\endrst
*/
*/
class
StringRef
{
template
<
typename
Char
>
class
BasicStringRef
{
private:
private:
const
c
har
*
data_
;
const
C
har
*
data_
;
mutable
std
::
size_t
size_
;
mutable
std
::
size_t
size_
;
public:
public:
...
@@ -255,32 +291,38 @@ class StringRef {
...
@@ -255,32 +291,38 @@ class StringRef {
If `size` is zero, which is the default, the size is computed with
If `size` is zero, which is the default, the size is computed with
`strlen`.
`strlen`.
*/
*/
StringRef
(
const
c
har
*
s
,
std
::
size_t
size
=
0
)
:
data_
(
s
),
size_
(
size
)
{}
BasicStringRef
(
const
C
har
*
s
,
std
::
size_t
size
=
0
)
:
data_
(
s
),
size_
(
size
)
{}
/**
/**
Constructs a string reference from an `std::string` object.
Constructs a string reference from an `std::string` object.
*/
*/
StringRef
(
const
std
::
string
&
s
)
:
data_
(
s
.
c_str
()),
size_
(
s
.
size
())
{}
BasicStringRef
(
const
std
::
basic_string
<
Char
>
&
s
)
:
data_
(
s
.
c_str
()),
size_
(
s
.
size
())
{}
/**
/**
Converts a string reference to an `std::string` object.
Converts a string reference to an `std::string` object.
*/
*/
operator
std
::
string
()
const
{
return
std
::
string
(
data_
,
size
());
}
operator
std
::
basic_string
<
Char
>
()
const
{
return
std
::
basic_string
<
Char
>
(
data_
,
size
());
}
/**
/**
Returns the pointer to a C string.
Returns the pointer to a C string.
*/
*/
const
c
har
*
c_str
()
const
{
return
data_
;
}
const
C
har
*
c_str
()
const
{
return
data_
;
}
/**
/**
Returns the string size.
Returns the string size.
*/
*/
std
::
size_t
size
()
const
{
std
::
size_t
size
()
const
{
if
(
size_
==
0
)
size_
=
std
::
strlen
(
data_
);
if
(
size_
==
0
)
size_
=
std
::
char_traits
<
Char
>::
length
(
data_
);
return
size_
;
return
size_
;
}
}
};
};
typedef
BasicStringRef
<
char
>
StringRef
;
typedef
BasicStringRef
<
wchar_t
>
WStringRef
;
class
FormatError
:
public
std
::
runtime_error
{
class
FormatError
:
public
std
::
runtime_error
{
public:
public:
explicit
FormatError
(
const
std
::
string
&
message
)
explicit
FormatError
(
const
std
::
string
&
message
)
...
@@ -729,8 +771,8 @@ void BasicWriter<Char>::FormatDouble(
...
@@ -729,8 +771,8 @@ void BasicWriter<Char>::FormatDouble(
// Build format string.
// Build format string.
enum
{
MAX_FORMAT_SIZE
=
10
};
// longest format: %#-*.*Lg
enum
{
MAX_FORMAT_SIZE
=
10
};
// longest format: %#-*.*Lg
c
har
format
[
MAX_FORMAT_SIZE
];
C
har
format
[
MAX_FORMAT_SIZE
];
c
har
*
format_ptr
=
format
;
C
har
*
format_ptr
=
format
;
*
format_ptr
++
=
'%'
;
*
format_ptr
++
=
'%'
;
unsigned
width_for_sprintf
=
width
;
unsigned
width_for_sprintf
=
width
;
if
(
spec
.
hash_flag
())
if
(
spec
.
hash_flag
())
...
@@ -755,18 +797,9 @@ void BasicWriter<Char>::FormatDouble(
...
@@ -755,18 +797,9 @@ void BasicWriter<Char>::FormatDouble(
// Format using snprintf.
// Format using snprintf.
for
(;;)
{
for
(;;)
{
std
::
size_t
size
=
buffer_
.
capacity
()
-
offset
;
std
::
size_t
size
=
buffer_
.
capacity
()
-
offset
;
int
n
=
0
;
Char
*
start
=
&
buffer_
[
offset
];
Char
*
start
=
&
buffer_
[
offset
];
if
(
width_for_sprintf
==
0
)
{
int
n
=
internal
::
CharTraits
<
Char
>::
FormatFloat
(
n
=
precision
<
0
?
start
,
size
,
format
,
width_for_sprintf
,
precision
,
value
);
FMT_SNPRINTF
(
start
,
size
,
format
,
value
)
:
FMT_SNPRINTF
(
start
,
size
,
format
,
precision
,
value
);
}
else
{
n
=
precision
<
0
?
FMT_SNPRINTF
(
start
,
size
,
format
,
width_for_sprintf
,
value
)
:
FMT_SNPRINTF
(
start
,
size
,
format
,
width_for_sprintf
,
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
)
||
...
@@ -953,7 +986,8 @@ class BasicFormatter {
...
@@ -953,7 +986,8 @@ class BasicFormatter {
// This method is private to disallow formatting of wide characters.
// This method is private to disallow formatting of wide characters.
// If you want to output a wide character cast it to integer type.
// If you want to output a wide character cast it to integer type.
// Do not implement!
// Do not implement!
Arg
(
wchar_t
value
);
// TODO
//Arg(wchar_t value);
public:
public:
Type
type
;
Type
type
;
...
@@ -1048,14 +1082,14 @@ class BasicFormatter {
...
@@ -1048,14 +1082,14 @@ class BasicFormatter {
args_
.
push_back
(
&
arg
);
args_
.
push_back
(
&
arg
);
}
}
void
ReportError
(
const
c
har
*
s
,
StringRef
message
)
const
;
void
ReportError
(
const
C
har
*
s
,
StringRef
message
)
const
;
unsigned
ParseUInt
(
const
c
har
*&
s
)
const
;
unsigned
ParseUInt
(
const
C
har
*&
s
)
const
;
// Parses argument index and returns an argument with this index.
// Parses argument index and returns an argument with this index.
const
Arg
&
ParseArgIndex
(
const
c
har
*&
s
);
const
Arg
&
ParseArgIndex
(
const
C
har
*&
s
);
void
CheckSign
(
const
c
har
*&
s
,
const
Arg
&
arg
);
void
CheckSign
(
const
C
har
*&
s
,
const
Arg
&
arg
);
void
DoFormat
();
void
DoFormat
();
...
@@ -1122,14 +1156,8 @@ inline std::basic_string<Char> str(const BasicWriter<Char> &f) {
...
@@ -1122,14 +1156,8 @@ inline std::basic_string<Char> str(const BasicWriter<Char> &f) {
template
<
typename
Char
>
template
<
typename
Char
>
inline
const
Char
*
c_str
(
const
BasicWriter
<
Char
>
&
f
)
{
return
f
.
c_str
();
}
inline
const
Char
*
c_str
(
const
BasicWriter
<
Char
>
&
f
)
{
return
f
.
c_str
();
}
std
::
string
str
(
internal
::
FormatterProxy
<
char
>
p
);
const
char
*
c_str
(
internal
::
FormatterProxy
<
char
>
p
);
namespace
internal
{
namespace
internal
{
using
fmt
::
str
;
using
fmt
::
c_str
;
template
<
typename
Char
>
template
<
typename
Char
>
class
FormatterProxy
{
class
FormatterProxy
{
private:
private:
...
@@ -1160,6 +1188,14 @@ inline const char *c_str(internal::FormatterProxy<char> p) {
...
@@ -1160,6 +1188,14 @@ inline const char *c_str(internal::FormatterProxy<char> p) {
return
p
.
Format
()
->
c_str
();
return
p
.
Format
()
->
c_str
();
}
}
inline
std
::
wstring
str
(
internal
::
FormatterProxy
<
wchar_t
>
p
)
{
return
p
.
Format
()
->
str
();
}
inline
const
wchar_t
*
c_str
(
internal
::
FormatterProxy
<
wchar_t
>
p
)
{
return
p
.
Format
()
->
c_str
();
}
/**
/**
A formatting action that does nothing.
A formatting action that does nothing.
*/
*/
...
@@ -1181,7 +1217,7 @@ class NoAction {
...
@@ -1181,7 +1217,7 @@ class NoAction {
struct PrintError {
struct PrintError {
void operator()(const fmt::Writer &w) const {
void operator()(const fmt::Writer &w) const {
std::cerr << "Error: " << w.str() << std::endl
;
fmt::Print("Error: {}\n") << w.str()
;
}
}
};
};
...
@@ -1204,10 +1240,10 @@ class Formatter : private Action, public BasicFormatter<Char> {
...
@@ -1204,10 +1240,10 @@ class Formatter : private Action, public BasicFormatter<Char> {
Formatter
&
operator
=
(
const
Formatter
&
);
Formatter
&
operator
=
(
const
Formatter
&
);
struct
Proxy
{
struct
Proxy
{
const
c
har
*
format
;
const
C
har
*
format
;
Action
action
;
Action
action
;
Proxy
(
const
c
har
*
fmt
,
Action
a
)
:
format
(
fmt
),
action
(
a
)
{}
Proxy
(
const
C
har
*
fmt
,
Action
a
)
:
format
(
fmt
),
action
(
a
)
{}
};
};
public:
public:
...
@@ -1220,7 +1256,7 @@ class Formatter : private Action, public BasicFormatter<Char> {
...
@@ -1220,7 +1256,7 @@ class Formatter : private Action, public BasicFormatter<Char> {
examples of action classes.
examples of action classes.
\endrst
\endrst
*/
*/
explicit
Formatter
(
StringRef
format
,
Action
a
=
Action
())
explicit
Formatter
(
BasicStringRef
<
Char
>
format
,
Action
a
=
Action
())
:
Action
(
a
),
BasicFormatter
<
Char
>
(
writer_
,
format
.
c_str
()),
:
Action
(
a
),
BasicFormatter
<
Char
>
(
writer_
,
format
.
c_str
()),
inactive_
(
false
)
{
inactive_
(
false
)
{
}
}
...
@@ -1277,6 +1313,10 @@ inline Formatter<> Format(StringRef format) {
...
@@ -1277,6 +1313,10 @@ inline Formatter<> Format(StringRef format) {
return
Formatter
<>
(
format
);
return
Formatter
<>
(
format
);
}
}
inline
Formatter
<
NoAction
,
wchar_t
>
Format
(
WStringRef
format
)
{
return
Formatter
<
NoAction
,
wchar_t
>
(
format
);
}
/** A formatting action that writes formatted output to stdout. */
/** A formatting action that writes formatted output to stdout. */
class
Write
{
class
Write
{
public:
public:
...
@@ -1297,7 +1337,7 @@ inline Formatter<Write> Print(StringRef format) {
...
@@ -1297,7 +1337,7 @@ inline Formatter<Write> Print(StringRef format) {
// FormatError reporting unmatched '{'. The idea is that unmatched '{'
// FormatError reporting unmatched '{'. The idea is that unmatched '{'
// should override other errors.
// should override other errors.
template
<
typename
Char
>
template
<
typename
Char
>
void
BasicFormatter
<
Char
>::
ReportError
(
const
c
har
*
s
,
StringRef
message
)
const
{
void
BasicFormatter
<
Char
>::
ReportError
(
const
C
har
*
s
,
StringRef
message
)
const
{
for
(
int
num_open_braces
=
num_open_braces_
;
*
s
;
++
s
)
{
for
(
int
num_open_braces
=
num_open_braces_
;
*
s
;
++
s
)
{
if
(
*
s
==
'{'
)
{
if
(
*
s
==
'{'
)
{
++
num_open_braces
;
++
num_open_braces
;
...
@@ -1312,7 +1352,7 @@ void BasicFormatter<Char>::ReportError(const char *s, StringRef message) const {
...
@@ -1312,7 +1352,7 @@ void BasicFormatter<Char>::ReportError(const char *s, StringRef message) const {
// 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
>
unsigned
BasicFormatter
<
Char
>::
ParseUInt
(
const
c
har
*&
s
)
const
{
unsigned
BasicFormatter
<
Char
>::
ParseUInt
(
const
C
har
*&
s
)
const
{
assert
(
'0'
<=
*
s
&&
*
s
<=
'9'
);
assert
(
'0'
<=
*
s
&&
*
s
<=
'9'
);
unsigned
value
=
0
;
unsigned
value
=
0
;
do
{
do
{
...
@@ -1326,7 +1366,7 @@ unsigned BasicFormatter<Char>::ParseUInt(const char *&s) const {
...
@@ -1326,7 +1366,7 @@ unsigned BasicFormatter<Char>::ParseUInt(const char *&s) const {
template
<
typename
Char
>
template
<
typename
Char
>
inline
const
typename
BasicFormatter
<
Char
>::
Arg
inline
const
typename
BasicFormatter
<
Char
>::
Arg
&
BasicFormatter
<
Char
>::
ParseArgIndex
(
const
c
har
*&
s
)
{
&
BasicFormatter
<
Char
>::
ParseArgIndex
(
const
C
har
*&
s
)
{
unsigned
arg_index
=
0
;
unsigned
arg_index
=
0
;
if
(
*
s
<
'0'
||
*
s
>
'9'
)
{
if
(
*
s
<
'0'
||
*
s
>
'9'
)
{
if
(
*
s
!=
'}'
&&
*
s
!=
':'
)
if
(
*
s
!=
'}'
&&
*
s
!=
':'
)
...
@@ -1350,7 +1390,7 @@ inline const typename BasicFormatter<Char>::Arg
...
@@ -1350,7 +1390,7 @@ inline const typename BasicFormatter<Char>::Arg
}
}
template
<
typename
Char
>
template
<
typename
Char
>
void
BasicFormatter
<
Char
>::
CheckSign
(
const
c
har
*&
s
,
const
Arg
&
arg
)
{
void
BasicFormatter
<
Char
>::
CheckSign
(
const
C
har
*&
s
,
const
Arg
&
arg
)
{
if
(
arg
.
type
>
LAST_NUMERIC_TYPE
)
{
if
(
arg
.
type
>
LAST_NUMERIC_TYPE
)
{
ReportError
(
s
,
ReportError
(
s
,
Format
(
"format specifier '{0}' requires numeric argument"
)
<<
*
s
);
Format
(
"format specifier '{0}' requires numeric argument"
)
<<
*
s
);
...
@@ -1369,7 +1409,7 @@ void BasicFormatter<Char>::DoFormat() {
...
@@ -1369,7 +1409,7 @@ void BasicFormatter<Char>::DoFormat() {
next_arg_index_
=
0
;
next_arg_index_
=
0
;
const
Char
*
s
=
start
;
const
Char
*
s
=
start
;
typedef
internal
::
Array
<
Char
,
BasicWriter
<
Char
>::
INLINE_BUFFER_SIZE
>
Buffer
;
typedef
internal
::
Array
<
Char
,
BasicWriter
<
Char
>::
INLINE_BUFFER_SIZE
>
Buffer
;
Writer
&
writer
=
*
writer_
;
BasicWriter
<
Char
>
&
writer
=
*
writer_
;
while
(
*
s
)
{
while
(
*
s
)
{
char
c
=
*
s
++
;
char
c
=
*
s
++
;
if
(
c
!=
'{'
&&
c
!=
'}'
)
continue
;
if
(
c
!=
'{'
&&
c
!=
'}'
)
continue
;
...
@@ -1392,7 +1432,7 @@ void BasicFormatter<Char>::DoFormat() {
...
@@ -1392,7 +1432,7 @@ void BasicFormatter<Char>::DoFormat() {
// Parse fill and alignment.
// Parse fill and alignment.
if
(
char
c
=
*
s
)
{
if
(
char
c
=
*
s
)
{
const
c
har
*
p
=
s
+
1
;
const
C
har
*
p
=
s
+
1
;
spec
.
align_
=
ALIGN_DEFAULT
;
spec
.
align_
=
ALIGN_DEFAULT
;
do
{
do
{
switch
(
*
p
)
{
switch
(
*
p
)
{
...
...
format_test.cc
View file @
bc6c1c17
...
@@ -1028,6 +1028,10 @@ TEST(FormatterTest, CustomFormat) {
...
@@ -1028,6 +1028,10 @@ TEST(FormatterTest, CustomFormat) {
EXPECT_EQ
(
"42"
,
str
(
Format
(
"{0}"
)
<<
Answer
()));
EXPECT_EQ
(
"42"
,
str
(
Format
(
"{0}"
)
<<
Answer
()));
}
}
TEST
(
FormatterTest
,
WideFormatString
)
{
EXPECT_EQ
(
L"42"
,
str
(
Format
(
L"{}"
)
<<
42
));
}
TEST
(
FormatterTest
,
FormatStringFromSpeedTest
)
{
TEST
(
FormatterTest
,
FormatStringFromSpeedTest
)
{
EXPECT_EQ
(
"1.2340000000:0042:+3.13:str:0x3e8:X:%"
,
EXPECT_EQ
(
"1.2340000000:0042:+3.13:str:0x3e8:X:%"
,
str
(
Format
(
"{0:0.10f}:{1:04}:{2:+g}:{3}:{4}:{5}:%"
)
str
(
Format
(
"{0:0.10f}:{1:04}:{2:+g}:{3}:{4}:{5}:%"
)
...
...
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