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
b98b2e98
Commit
b98b2e98
authored
Dec 10, 2012
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement formatting of integers.
parent
c5dce1ca
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
310 additions
and
185 deletions
+310
-185
format.cc
format.cc
+198
-127
format.h
format.h
+19
-19
format_test.cc
format_test.cc
+93
-39
No files found.
format.cc
View file @
b98b2e98
...
...
@@ -5,6 +5,8 @@
#include "format.h"
#include <stdint.h>
#include <cassert>
#include <climits>
#include <cstring>
...
...
@@ -14,16 +16,16 @@ using std::size_t;
namespace
{
// Flags.
enum
{
PLUS_FLAG
=
1
,
ZERO_FLAG
=
2
,
HEX_PREFIX_FLAG
=
4
};
// Throws Exception(message) if format contains '}', otherwise throws
// FormatError reporting unmatched '{'. The idea is that unmatched '{'
// should override other errors.
template
<
typename
Exception
>
void
Throw
(
const
char
*
s
,
const
char
*
message
)
{
void
ReportError
(
const
char
*
s
,
const
std
::
string
&
message
)
{
while
(
*
s
&&
*
s
!=
'}'
)
++
s
;
if
(
!*
s
)
throw
fmt
::
FormatError
(
"unmatched '{' in format"
);
throw
Exception
(
message
);
throw
fmt
::
FormatError
(
*
s
?
message
:
std
::
string
(
"unmatched '{' in format"
));
}
// Parses an unsigned integer advancing s to the end of the parsed input.
...
...
@@ -34,29 +36,168 @@ unsigned ParseUInt(const char *&s) {
do
{
unsigned
new_value
=
value
*
10
+
(
*
s
++
-
'0'
);
if
(
new_value
<
value
)
// Check if value wrapped around.
Throw
<
fmt
::
FormatError
>
(
s
,
"number is too big in format"
);
ReportError
(
s
,
"number is too big in format"
);
value
=
new_value
;
}
while
(
'0'
<=
*
s
&&
*
s
<=
'9'
);
return
value
;
}
// Maps an integer type T to its unsigned counterpart.
template
<
typename
T
>
struct
GetUnsigned
;
template
<
>
struct
GetUnsigned
<
int
>
{
typedef
unsigned
Type
;
};
template
<
>
struct
GetUnsigned
<
unsigned
>
{
typedef
unsigned
Type
;
};
template
<
>
struct
GetUnsigned
<
long
>
{
typedef
unsigned
long
Type
;
};
template
<
>
struct
GetUnsigned
<
unsigned
long
>
{
typedef
unsigned
long
Type
;
};
template
<
typename
T
>
struct
IsLongDouble
{
enum
{
VALUE
=
0
};
};
template
<
>
struct
IsLongDouble
<
long
double
>
{
enum
{
VALUE
=
1
};
};
}
template
<
typename
T
>
void
fmt
::
Formatter
::
FormatInt
(
T
value
,
unsigned
flags
,
int
width
,
char
type
)
{
int
size
=
0
;
char
sign
=
0
;
typedef
typename
GetUnsigned
<
T
>::
Type
UnsignedType
;
UnsignedType
abs_value
=
value
;
if
(
value
<
0
)
{
sign
=
'-'
;
++
size
;
abs_value
=
-
value
;
}
else
if
((
flags
&
PLUS_FLAG
)
!=
0
)
{
sign
=
'+'
;
++
size
;
}
char
fill
=
(
flags
&
ZERO_FLAG
)
!=
0
?
'0'
:
' '
;
size_t
start
=
buffer_
.
size
();
char
*
p
=
0
;
switch
(
type
)
{
case
0
:
case
'd'
:
{
UnsignedType
n
=
abs_value
;
do
{
++
size
;
}
while
((
n
/=
10
)
!=
0
);
width
=
std
::
max
(
width
,
size
);
buffer_
.
resize
(
buffer_
.
size
()
+
width
,
fill
);
p
=
&
buffer_
.
back
();
n
=
abs_value
;
do
{
*
p
--
=
'0'
+
(
n
%
10
);
}
while
((
n
/=
10
)
!=
0
);
break
;
}
case
'x'
:
case
'X'
:
{
UnsignedType
n
=
abs_value
;
bool
print_prefix
=
(
flags
&
HEX_PREFIX_FLAG
)
!=
0
;
if
(
print_prefix
)
size
+=
2
;
do
{
++
size
;
}
while
((
n
>>=
4
)
!=
0
);
width
=
std
::
max
(
width
,
size
);
buffer_
.
resize
(
buffer_
.
size
()
+
width
,
fill
);
p
=
&
buffer_
.
back
();
n
=
abs_value
;
const
char
*
digits
=
type
==
'x'
?
"0123456789abcdef"
:
"0123456789ABCDEF"
;
do
{
*
p
--
=
digits
[
n
&
0xf
];
}
while
((
n
>>=
4
)
!=
0
);
if
(
print_prefix
)
{
*
p
--
=
type
;
*
p
--
=
'0'
;
}
break
;
}
case
'o'
:
{
UnsignedType
n
=
abs_value
;
do
{
++
size
;
}
while
((
n
>>=
3
)
!=
0
);
width
=
std
::
max
(
width
,
size
);
buffer_
.
resize
(
buffer_
.
size
()
+
width
,
fill
);
p
=
&
buffer_
.
back
();
n
=
abs_value
;
do
{
*
p
--
=
'0'
+
(
n
&
7
);
}
while
((
n
>>=
3
)
!=
0
);
break
;
}
default:
throw
FormatError
(
str
(
fmt
::
Format
(
"unknown format code '{0}' for integer"
)
<<
type
));
}
if
(
sign
)
{
if
((
flags
&
ZERO_FLAG
)
!=
0
)
buffer_
[
start
]
=
sign
;
else
*
p
=
sign
;
}
}
template
<
typename
T
>
void
fmt
::
Formatter
::
FormatBuiltinArg
(
const
char
*
format
,
const
T
&
arg
,
int
width
,
int
precision
)
{
void
fmt
::
Formatter
::
FormatDouble
(
T
value
,
unsigned
flags
,
int
width
,
int
precision
,
char
type
)
{
// Check type.
switch
(
type
)
{
case
'e'
:
case
'E'
:
case
'f'
:
case
'F'
:
case
'g'
:
case
'G'
:
break
;
default:
// TODO: error
break
;
}
// Build format string.
enum
{
MAX_FORMAT_SIZE
=
9
};
// longest format: %+0*.*Lg
char
format
[
MAX_FORMAT_SIZE
];
char
*
format_ptr
=
format
;
*
format_ptr
++
=
'%'
;
if
((
flags
&
PLUS_FLAG
)
!=
0
)
*
format_ptr
++
=
'+'
;
if
((
flags
&
ZERO_FLAG
)
!=
0
)
*
format_ptr
++
=
'0'
;
if
(
width
>
0
)
*
format_ptr
++
=
'*'
;
if
(
precision
>=
0
)
{
*
format_ptr
++
=
'.'
;
*
format_ptr
++
=
'*'
;
}
if
(
IsLongDouble
<
T
>::
VALUE
)
*
format_ptr
++
=
'L'
;
*
format_ptr
++
=
type
?
type
:
'g'
;
*
format_ptr
=
'\0'
;
// Format using snprintf.
size_t
offset
=
buffer_
.
size
();
buffer_
.
resize
(
buffer_
.
capacity
());
for
(;;)
{
size_t
size
=
buffer_
.
size
()
-
offset
;
int
n
=
0
;
if
(
width
<
0
)
{
if
(
width
<
=
0
)
{
n
=
precision
<
0
?
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
arg
)
:
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
precision
,
arg
);
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
value
)
:
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
precision
,
value
);
}
else
{
n
=
precision
<
0
?
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
width
,
arg
)
:
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
width
,
precision
,
arg
);
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
width
,
value
)
:
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
width
,
precision
,
value
);
}
if
(
n
>=
0
&&
offset
+
n
<
buffer_
.
size
())
{
buffer_
.
resize
(
offset
+
n
);
...
...
@@ -77,92 +218,64 @@ void fmt::Formatter::Format() {
// Parse argument index.
if
(
*
s
<
'0'
||
*
s
>
'9'
)
Throw
<
fmt
::
FormatError
>
(
s
,
"missing argument index in format string"
);
ReportError
(
s
,
"missing argument index in format string"
);
unsigned
arg_index
=
ParseUInt
(
s
);
if
(
arg_index
>=
args_
.
size
())
Throw
<
std
::
out_of_range
>
(
s
,
"argument index is out of range in format"
);
ReportError
(
s
,
"argument index is out of range in format"
);
Arg
&
arg
=
args_
[
arg_index
];
enum
{
MAX_FORMAT_SIZE
=
10
};
// longest format: %+0-*.*ld
char
arg_format
[
MAX_FORMAT_SIZE
];
char
*
arg_format_ptr
=
arg_format
;
*
arg_format_ptr
++
=
'%'
;
int
width
=
-
1
;
unsigned
flags
=
0
;
int
width
=
0
;
int
precision
=
-
1
;
char
type
=
0
;
bool
is_floating_point
=
false
;
if
(
*
s
==
':'
)
{
++
s
;
if
(
*
s
==
'+'
)
{
if
(
arg
.
type
>
LAST_NUMERIC_TYPE
)
{
Throw
<
FormatError
>
(
s
,
"format specifier '+' requires numeric argument"
);
}
++
s
;
if
(
arg
.
type
>
LAST_NUMERIC_TYPE
)
ReportError
(
s
,
"format specifier '+' requires numeric argument"
);
if
(
arg
.
type
==
UINT
||
arg
.
type
==
ULONG
)
{
Throw
<
FormatError
>
(
s
,
ReportError
(
s
,
"format specifier '+' requires signed argument"
);
}
*
arg_format_ptr
++
=
*
s
++
;
flags
|=
PLUS_FLAG
;
}
if
(
*
s
==
'0'
)
{
if
(
arg
.
type
>
LAST_NUMERIC_TYPE
)
{
Throw
<
FormatError
>
(
s
,
"format specifier '0' requires numeric argument"
);
}
*
arg_format_ptr
++
=
*
s
++
;
++
s
;
if
(
arg
.
type
>
LAST_NUMERIC_TYPE
)
ReportError
(
s
,
"format specifier '0' requires numeric argument"
);
flags
|=
ZERO_FLAG
;
}
// Parse width.
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
if
(
arg
.
type
>
LAST_NUMERIC_TYPE
&&
arg
.
type
!=
POINTER
)
*
arg_format_ptr
++
=
'-'
;
*
arg_format_ptr
++
=
'*'
;
unsigned
value
=
ParseUInt
(
s
);
if
(
value
>
INT_MAX
)
Throw
<
FormatError
>
(
s
,
"number is too big in format"
);
ReportError
(
s
,
"number is too big in format"
);
width
=
value
;
}
// Parse precision.
if
(
*
s
==
'.'
)
{
*
arg_format_ptr
++
=
'.'
;
*
arg_format_ptr
++
=
'*'
;
++
s
;
precision
=
0
;
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
unsigned
value
=
ParseUInt
(
s
);
if
(
value
>
INT_MAX
)
Throw
<
FormatError
>
(
s
,
"number is too big in format"
);
ReportError
(
s
,
"number is too big in format"
);
precision
=
value
;
}
else
{
Throw
<
FormatError
>
(
s
,
"missing precision in format"
);
ReportError
(
s
,
"missing precision in format"
);
}
if
(
arg
.
type
>
LAST_NUMERIC_TYPE
||
(
*
s
==
'}'
&&
arg
.
type
!=
DOUBLE
&&
arg
.
type
!=
LONG_DOUBLE
))
{
Throw
<
FormatError
>
(
s
,
"precision specifier requires floating-point type"
);
if
(
arg
.
type
!=
DOUBLE
&&
arg
.
type
!=
LONG_DOUBLE
)
{
ReportError
(
s
,
"precision specifier requires floating-point argument"
);
}
}
// Parse type.
if
(
*
s
!=
'}'
&&
*
s
)
{
if
(
*
s
!=
'}'
&&
*
s
)
type
=
*
s
++
;
if
(
arg
.
type
<=
LAST_NUMERIC_TYPE
)
{
switch
(
type
)
{
case
'd'
:
case
'o'
:
case
'x'
:
case
'X'
:
// TODO: check that argument is integer
break
;
case
'e'
:
case
'E'
:
case
'f'
:
case
'F'
:
case
'g'
:
case
'G'
:
is_floating_point
=
true
;
break
;
default:
// TODO: error
break
;
}
}
// TODO: check non-numeric types (string, character)
}
}
if
(
*
s
++
!=
'}'
)
...
...
@@ -172,87 +285,45 @@ void fmt::Formatter::Format() {
// Format argument.
switch
(
arg
.
type
)
{
case
INT
:
*
arg_format_ptr
++
=
type
?
type
:
'd'
;
*
arg_format_ptr
=
'\0'
;
if
(
is_floating_point
)
FormatBuiltinArg
<
double
>
(
arg_format
,
arg
.
int_value
,
width
,
precision
);
else
FormatBuiltinArg
(
arg_format
,
arg
.
int_value
,
width
,
precision
);
FormatInt
(
arg
.
int_value
,
flags
,
width
,
type
);
break
;
case
UINT
:
*
arg_format_ptr
++
=
type
?
type
:
'u'
;
*
arg_format_ptr
=
'\0'
;
if
(
is_floating_point
)
FormatBuiltinArg
<
double
>
(
arg_format
,
arg
.
uint_value
,
width
,
precision
);
else
FormatBuiltinArg
(
arg_format
,
arg
.
uint_value
,
width
,
precision
);
FormatInt
(
arg
.
uint_value
,
flags
,
width
,
type
);
break
;
case
LONG
:
*
arg_format_ptr
++
=
'l'
;
*
arg_format_ptr
++
=
type
?
type
:
'd'
;
*
arg_format_ptr
=
'\0'
;
if
(
is_floating_point
)
FormatBuiltinArg
<
double
>
(
arg_format
,
arg
.
long_value
,
width
,
precision
);
else
FormatBuiltinArg
(
arg_format
,
arg
.
long_value
,
width
,
precision
);
FormatInt
(
arg
.
long_value
,
flags
,
width
,
type
);
break
;
case
ULONG
:
*
arg_format_ptr
++
=
'l'
;
*
arg_format_ptr
++
=
type
?
type
:
'u'
;
*
arg_format_ptr
=
'\0'
;
if
(
is_floating_point
)
FormatBuiltinArg
<
double
>
(
arg_format
,
arg
.
ulong_value
,
width
,
precision
);
else
FormatBuiltinArg
(
arg_format
,
arg
.
ulong_value
,
width
,
precision
);
FormatInt
(
arg
.
ulong_value
,
flags
,
width
,
type
);
break
;
case
DOUBLE
:
*
arg_format_ptr
++
=
type
?
type
:
'g'
;
*
arg_format_ptr
=
'\0'
;
FormatBuiltinArg
(
arg_format
,
arg
.
double_value
,
width
,
precision
);
FormatDouble
(
arg
.
double_value
,
flags
,
width
,
precision
,
type
);
break
;
case
LONG_DOUBLE
:
*
arg_format_ptr
++
=
'L'
;
*
arg_format_ptr
++
=
type
?
type
:
'g'
;
*
arg_format_ptr
=
'\0'
;
FormatBuiltinArg
(
arg_format
,
arg
.
long_double_value
,
width
,
precision
);
break
;
case
POINTER
:
// TODO: don't allow any type specifiers other than 'p'
*
arg_format_ptr
++
=
'p'
;
*
arg_format_ptr
=
'\0'
;
FormatBuiltinArg
(
arg_format
,
arg
.
pointer_value
,
width
,
precision
);
FormatDouble
(
arg
.
long_double_value
,
flags
,
width
,
precision
,
type
);
break
;
case
CHAR
:
// TODO: check if type is 'c' or none
if
(
width
<=
1
)
{
buffer_
.
push_back
(
arg
.
int_value
);
break
;
}
*
arg_format_ptr
++
=
'c'
;
*
arg_format_ptr
=
'\0'
;
FormatBuiltinArg
(
arg_format
,
arg
.
int_value
,
width
,
precision
);
buffer_
.
reserve
(
std
::
max
(
width
,
1
));
buffer_
.
push_back
(
arg
.
int_value
);
if
(
width
>
1
)
buffer_
.
resize
(
buffer_
.
size
()
+
width
-
1
,
' '
);
break
;
case
STRING
:
// TODO: check if type is 's' or none
if
(
width
==
-
1
||
width
<=
arg
.
size
)
{
const
char
*
str
=
arg
.
string_value
;
size_t
size
=
arg
.
size
;
if
(
size
==
0
&&
*
str
)
size
=
std
::
strlen
(
str
);
buffer_
.
reserve
(
buffer_
.
size
()
+
size
+
1
);
buffer_
.
insert
(
buffer_
.
end
(),
str
,
str
+
size
);
break
;
}
*
arg_format_ptr
++
=
's'
;
*
arg_format_ptr
=
'\0'
;
FormatBuiltinArg
(
arg_format
,
arg
.
string_value
,
width
,
precision
);
case
STRING
:
{
const
char
*
str
=
arg
.
string_value
;
size_t
size
=
arg
.
size
;
if
(
size
==
0
&&
*
str
)
size
=
std
::
strlen
(
str
);
buffer_
.
reserve
(
buffer_
.
size
()
+
std
::
max
<
size_t
>
(
width
,
size
));
buffer_
.
insert
(
buffer_
.
end
(),
str
,
str
+
size
);
if
(
width
>
size
)
buffer_
.
resize
(
buffer_
.
size
()
+
width
-
size
,
' '
);
break
;
case
WSTRING
:
// TODO: check if type is 's' or none
*
arg_format_ptr
++
=
'l'
;
*
arg_format_ptr
++
=
's'
;
*
arg_format_ptr
=
'\0'
;
FormatBuiltinArg
(
arg_format
,
arg
.
wstring_value
,
width
,
precision
);
}
case
POINTER
:
// TODO: don't allow type specifiers other than 'p'
FormatInt
(
reinterpret_cast
<
uintptr_t
>
(
arg
.
pointer_value
),
HEX_PREFIX_FLAG
,
width
,
'x'
);
break
;
case
CUSTOM
:
// TODO: check if type is 's' or none
...
...
format.h
View file @
b98b2e98
...
...
@@ -53,7 +53,6 @@ class Formatter {
struct
{
union
{
const
char
*
string_value
;
const
wchar_t
*
wstring_value
;
const
void
*
pointer_value
;
};
std
::
size_t
size
;
...
...
@@ -74,7 +73,6 @@ class Formatter {
explicit
Arg
(
char
value
)
:
type
(
CHAR
),
int_value
(
value
)
{}
explicit
Arg
(
const
char
*
value
,
std
::
size_t
size
=
0
)
:
type
(
STRING
),
string_value
(
value
),
size
(
size
)
{}
explicit
Arg
(
const
wchar_t
*
value
)
:
type
(
WSTRING
),
wstring_value
(
value
)
{}
explicit
Arg
(
const
void
*
value
)
:
type
(
POINTER
),
pointer_value
(
value
)
{}
explicit
Arg
(
const
void
*
value
,
FormatFunc
f
)
:
type
(
CUSTOM
),
custom_value
(
value
),
format
(
f
)
{}
...
...
@@ -92,10 +90,14 @@ class Formatter {
args_
.
push_back
(
arg
);
}
// Formats an
argument of a built-in type, such as "int" or "double"
.
// Formats an
integer
.
template
<
typename
T
>
void
FormatBuiltinArg
(
const
char
*
format
,
const
T
&
arg
,
int
width
,
int
precision
);
void
FormatInt
(
T
value
,
unsigned
flags
,
int
width
,
char
type
);
// Formats a floating point number.
template
<
typename
T
>
void
FormatDouble
(
T
value
,
unsigned
flags
,
int
width
,
int
precision
,
char
type
);
// Formats an argument of a custom type, such as a user-defined class.
template
<
typename
T
>
...
...
@@ -199,11 +201,6 @@ class ArgFormatter {
return
*
this
;
}
ArgFormatter
&
operator
<<
(
const
wchar_t
*
value
)
{
formatter_
->
Add
(
Formatter
::
Arg
(
value
));
return
*
this
;
}
ArgFormatter
&
operator
<<
(
const
std
::
string
&
value
)
{
formatter_
->
Add
(
Formatter
::
Arg
(
value
.
c_str
(),
value
.
size
()));
return
*
this
;
...
...
@@ -214,10 +211,16 @@ class ArgFormatter {
return
*
this
;
}
// This method
is not implemented intentionally to disallow output of
// This method
contains a deliberate error to disallow formatting
// arbitrary pointers. If you want to output a pointer cast it to void*.
template
<
typename
T
>
ArgFormatter
&
operator
<<
(
const
T
*
value
);
ArgFormatter
&
operator
<<
(
const
T
*
value
)
{
"Formatting arbitrary pointers is not allowed"
=
value
;
}
// This method is not implemented intentionally to disallow formatting
// wide characters.
ArgFormatter
&
operator
<<
(
wchar_t
value
);
template
<
typename
T
>
ArgFormatter
&
operator
<<
(
T
*
value
)
{
...
...
@@ -253,13 +256,10 @@ void Formatter::FormatCustomArg(const void *arg, int width) {
std
::
ostringstream
os
;
os
<<
value
;
std
::
string
str
(
os
.
str
());
if
(
width
<
0
)
{
// Extra char is reserved for terminating '\0'.
buffer_
.
reserve
(
buffer_
.
size
()
+
str
.
size
()
+
1
);
buffer_
.
insert
(
buffer_
.
end
(),
str
.
begin
(),
str
.
end
());
return
;
}
FormatBuiltinArg
(
"%-*s"
,
str
.
c_str
(),
width
,
-
1
);
buffer_
.
reserve
(
buffer_
.
size
()
+
std
::
max
<
std
::
size_t
>
(
width
,
str
.
size
()));
buffer_
.
insert
(
buffer_
.
end
(),
str
.
begin
(),
str
.
end
());
if
(
width
>
str
.
size
())
buffer_
.
resize
(
buffer_
.
size
()
+
width
-
str
.
size
(),
' '
);
}
inline
ArgFormatter
Formatter
::
operator
()(
const
char
*
format
)
{
...
...
format_test.cc
View file @
b98b2e98
...
...
@@ -71,7 +71,7 @@ TEST(FormatterTest, NoArgs) {
EXPECT_EQ
(
"test"
,
str
(
Format
(
"test"
)));
}
TEST
(
FormatterTest
,
Args
)
{
TEST
(
FormatterTest
,
Args
InDifferentPositions
)
{
EXPECT_EQ
(
"42"
,
str
(
Format
(
"{0}"
)
<<
42
));
EXPECT_EQ
(
"before 42"
,
str
(
Format
(
"before {0}"
)
<<
42
));
EXPECT_EQ
(
"42 after"
,
str
(
Format
(
"{0} after"
)
<<
42
));
...
...
@@ -86,13 +86,13 @@ TEST(FormatterTest, ArgErrors) {
EXPECT_THROW_MSG
(
Format
(
"{}"
),
FormatError
,
"missing argument index in format string"
);
EXPECT_THROW_MSG
(
Format
(
"{0"
),
FormatError
,
"unmatched '{' in format"
);
EXPECT_THROW_MSG
(
Format
(
"{0}"
),
std
::
out_of_range
,
EXPECT_THROW_MSG
(
Format
(
"{0}"
),
FormatError
,
"argument index is out of range in format"
);
char
format
[
256
];
std
::
sprintf
(
format
,
"{%u"
,
UINT_MAX
);
EXPECT_THROW_MSG
(
Format
(
format
),
FormatError
,
"unmatched '{' in format"
);
std
::
sprintf
(
format
,
"{%u}"
,
UINT_MAX
);
EXPECT_THROW_MSG
(
Format
(
format
),
std
::
out_of_range
,
EXPECT_THROW_MSG
(
Format
(
format
),
FormatError
,
"argument index is out of range in format"
);
if
(
ULONG_MAX
>
UINT_MAX
)
{
std
::
sprintf
(
format
,
"{%lu"
,
UINT_MAX
+
1l
);
...
...
@@ -130,8 +130,6 @@ TEST(FormatterTest, PlusFlag) {
FormatError
,
"format specifier '+' requires numeric argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:+}"
)
<<
"abc"
,
FormatError
,
"format specifier '+' requires numeric argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:+}"
)
<<
L"abc"
,
FormatError
,
"format specifier '+' requires numeric argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:+}"
)
<<
reinterpret_cast
<
void
*>
(
0x42
),
FormatError
,
"format specifier '+' requires numeric argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:+}"
)
<<
TestString
(),
...
...
@@ -152,8 +150,6 @@ TEST(FormatterTest, ZeroFlag) {
FormatError
,
"format specifier '0' requires numeric argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:05}"
)
<<
"abc"
,
FormatError
,
"format specifier '0' requires numeric argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:05}"
)
<<
L"abc"
,
FormatError
,
"format specifier '0' requires numeric argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:05}"
)
<<
reinterpret_cast
<
void
*>
(
0x42
),
FormatError
,
"format specifier '0' requires numeric argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:05}"
)
<<
TestString
(),
...
...
@@ -189,9 +185,8 @@ TEST(FormatterTest, Width) {
EXPECT_EQ
(
" 0xcafe"
,
str
(
Format
(
"{0:10}"
)
<<
reinterpret_cast
<
void
*>
(
0xcafe
)));
EXPECT_EQ
(
"x "
,
str
(
Format
(
"{0:11}"
)
<<
'x'
));
EXPECT_EQ
(
"narrow "
,
str
(
Format
(
"{0:12}"
)
<<
"narrow"
));
EXPECT_EQ
(
"wide "
,
str
(
Format
(
"{0:13}"
)
<<
L"wide"
));
EXPECT_EQ
(
"test "
,
str
(
Format
(
"{0:14}"
)
<<
TestString
(
"test"
)));
EXPECT_EQ
(
"str "
,
str
(
Format
(
"{0:12}"
)
<<
"str"
));
EXPECT_EQ
(
"test "
,
str
(
Format
(
"{0:13}"
)
<<
TestString
(
"test"
)));
}
TEST
(
FormatterTest
,
Precision
)
{
...
...
@@ -224,55 +219,97 @@ TEST(FormatterTest, Precision) {
FormatError
,
"unmatched '{' in format"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2}"
)
<<
42
,
FormatError
,
"precision specifier requires floating-point type"
);
EXPECT_EQ
(
"42.00"
,
str
(
Format
(
"{0:.2f}"
)
<<
42
));
FormatError
,
"precision specifier requires floating-point argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2f}"
)
<<
42
,
FormatError
,
"precision specifier requires floating-point argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2}"
)
<<
42u
,
FormatError
,
"precision specifier requires floating-point type"
);
EXPECT_EQ
(
"42.00"
,
str
(
Format
(
"{0:.2f}"
)
<<
42u
));
FormatError
,
"precision specifier requires floating-point argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2f}"
)
<<
42u
,
FormatError
,
"precision specifier requires floating-point argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2}"
)
<<
42l
,
FormatError
,
"precision specifier requires floating-point type"
);
EXPECT_EQ
(
"42.00"
,
str
(
Format
(
"{0:.2f}"
)
<<
42l
));
FormatError
,
"precision specifier requires floating-point argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2f}"
)
<<
42l
,
FormatError
,
"precision specifier requires floating-point argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2}"
)
<<
42ul
,
FormatError
,
"precision specifier requires floating-point type"
);
EXPECT_EQ
(
"42.00"
,
str
(
Format
(
"{0:.2f}"
)
<<
42ul
));
FormatError
,
"precision specifier requires floating-point argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2f}"
)
<<
42ul
,
FormatError
,
"precision specifier requires floating-point argument"
);
EXPECT_EQ
(
"1.2"
,
str
(
Format
(
"{0:.2}"
)
<<
1.2345
));
EXPECT_EQ
(
"1.2"
,
str
(
Format
(
"{0:.2}"
)
<<
1.2345
l
));
EXPECT_THROW_MSG
(
Format
(
"{0:.2}"
)
<<
reinterpret_cast
<
void
*>
(
0xcafe
),
FormatError
,
"precision specifier requires floating-point
type
"
);
FormatError
,
"precision specifier requires floating-point
argument
"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2f}"
)
<<
reinterpret_cast
<
void
*>
(
0xcafe
),
FormatError
,
"precision specifier requires floating-point
type
"
);
FormatError
,
"precision specifier requires floating-point
argument
"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2}"
)
<<
'x'
,
FormatError
,
"precision specifier requires floating-point
type
"
);
FormatError
,
"precision specifier requires floating-point
argument
"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2f}"
)
<<
'x'
,
FormatError
,
"precision specifier requires floating-point
type
"
);
FormatError
,
"precision specifier requires floating-point
argument
"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2}"
)
<<
"str"
,
FormatError
,
"precision specifier requires floating-point
type
"
);
FormatError
,
"precision specifier requires floating-point
argument
"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2f}"
)
<<
"str"
,
FormatError
,
"precision specifier requires floating-point type"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2}"
)
<<
L"str"
,
FormatError
,
"precision specifier requires floating-point type"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2f}"
)
<<
L"str"
,
FormatError
,
"precision specifier requires floating-point type"
);
FormatError
,
"precision specifier requires floating-point argument"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2}"
)
<<
TestString
(),
FormatError
,
"precision specifier requires floating-point
type
"
);
FormatError
,
"precision specifier requires floating-point
argument
"
);
EXPECT_THROW_MSG
(
Format
(
"{0:.2f}"
)
<<
TestString
(),
FormatError
,
"precision specifier requires floating-point type"
);
FormatError
,
"precision specifier requires floating-point argument"
);
}
TEST
(
FormatterTest
,
Type
)
{
EXPECT_THROW_MSG
(
Format
(
"{0:v"
)
<<
42
,
FormatError
,
"unmatched '{' in format"
);
EXPECT_THROW_MSG
(
Format
(
"{0:v}"
)
<<
42
,
FormatError
,
"unknown format code 'v' for integer"
);
}
TEST
(
FormatterTest
,
FormatInt
)
{
TEST
(
FormatterTest
,
FormatDec
)
{
EXPECT_EQ
(
"0"
,
str
(
Format
(
"{0}"
)
<<
0
));
EXPECT_EQ
(
"42"
,
str
(
Format
(
"{0}"
)
<<
42
));
EXPECT_EQ
(
"-1234"
,
str
(
Format
(
"{0}"
)
<<
-
1234
));
std
::
ostringstream
os
;
os
<<
INT_MIN
;
EXPECT_EQ
(
os
.
str
(),
str
(
Format
(
"{0}"
)
<<
INT_MIN
));
os
.
str
(
std
::
string
());
os
<<
INT_MAX
;
EXPECT_EQ
(
os
.
str
(),
str
(
Format
(
"{0}"
)
<<
INT_MAX
));
EXPECT_EQ
(
"42"
,
str
(
Format
(
"{0:d}"
)
<<
42
));
EXPECT_EQ
(
"42"
,
str
(
Format
(
"{0}"
)
<<
42u
));
EXPECT_EQ
(
"-42"
,
str
(
Format
(
"{0}"
)
<<
-
42
));
EXPECT_EQ
(
"12345"
,
str
(
Format
(
"{0}"
)
<<
12345
));
EXPECT_EQ
(
"67890"
,
str
(
Format
(
"{0}"
)
<<
67890
));
char
buffer
[
256
];
sprintf
(
buffer
,
"%d"
,
INT_MIN
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0}"
)
<<
INT_MIN
));
sprintf
(
buffer
,
"%d"
,
INT_MAX
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0}"
)
<<
INT_MAX
));
sprintf
(
buffer
,
"%u"
,
UINT_MAX
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0}"
)
<<
UINT_MAX
));
sprintf
(
buffer
,
"%ld"
,
0ul
-
LONG_MIN
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0}"
)
<<
LONG_MIN
));
sprintf
(
buffer
,
"%ld"
,
LONG_MAX
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0}"
)
<<
LONG_MAX
));
sprintf
(
buffer
,
"%lu"
,
ULONG_MAX
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0}"
)
<<
ULONG_MAX
));
}
TEST
(
FormatterTest
,
FormatHex
)
{
EXPECT_EQ
(
"0"
,
str
(
Format
(
"{0:x}"
)
<<
0
));
EXPECT_EQ
(
"42"
,
str
(
Format
(
"{0:x}"
)
<<
0x42
));
EXPECT_EQ
(
"42"
,
str
(
Format
(
"{0:x}"
)
<<
0x42u
));
EXPECT_EQ
(
"-42"
,
str
(
Format
(
"{0:x}"
)
<<
-
0x42
));
EXPECT_EQ
(
"12345678"
,
str
(
Format
(
"{0:x}"
)
<<
0x12345678
));
EXPECT_EQ
(
"90abcdef"
,
str
(
Format
(
"{0:x}"
)
<<
0x90abcdef
));
EXPECT_EQ
(
"12345678"
,
str
(
Format
(
"{0:X}"
)
<<
0x12345678
));
EXPECT_EQ
(
"90ABCDEF"
,
str
(
Format
(
"{0:X}"
)
<<
0x90ABCDEF
));
char
buffer
[
256
];
sprintf
(
buffer
,
"-%x"
,
0u
-
INT_MIN
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0:x}"
)
<<
INT_MIN
));
sprintf
(
buffer
,
"%x"
,
INT_MAX
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0:x}"
)
<<
INT_MAX
));
sprintf
(
buffer
,
"%x"
,
UINT_MAX
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0:x}"
)
<<
UINT_MAX
));
sprintf
(
buffer
,
"-%lx"
,
0ul
-
LONG_MIN
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0:x}"
)
<<
LONG_MIN
));
sprintf
(
buffer
,
"%lx"
,
LONG_MAX
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0:x}"
)
<<
LONG_MAX
));
sprintf
(
buffer
,
"%lx"
,
ULONG_MAX
);
EXPECT_EQ
(
buffer
,
str
(
Format
(
"{0:x}"
)
<<
ULONG_MAX
));
}
TEST
(
FormatterTest
,
FormatChar
)
{
...
...
@@ -283,8 +320,25 @@ TEST(FormatterTest, FormatString) {
EXPECT_EQ
(
"test"
,
str
(
Format
(
"{0}"
)
<<
std
::
string
(
"test"
)));
}
TEST
(
FormatterTest
,
FormatPointer
)
{
EXPECT_EQ
(
"0x0"
,
str
(
Format
(
"{0}"
)
<<
reinterpret_cast
<
void
*>
(
0
)));
}
class
Date
{
int
year_
,
month_
,
day_
;
public:
Date
(
int
year
,
int
month
,
int
day
)
:
year_
(
year
),
month_
(
month
),
day_
(
day
)
{}
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Date
&
d
)
{
os
<<
d
.
year_
<<
'-'
<<
d
.
month_
<<
'-'
<<
d
.
day_
;
return
os
;
}
};
TEST
(
FormatterTest
,
FormatCustomArg
)
{
EXPECT_EQ
(
"a string"
,
str
(
Format
(
"{0}"
)
<<
TestString
(
"a string"
)));
std
::
string
s
=
str
(
fmt
::
Format
(
"The date is {0}"
)
<<
Date
(
2012
,
12
,
9
));
EXPECT_EQ
(
"The date is 2012-12-9"
,
s
);
}
TEST
(
FormatterTest
,
FormatStringFromSpeedTest
)
{
...
...
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