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
b076df4f
Commit
b076df4f
authored
Dec 07, 2012
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial import
parent
ec27d5d8
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
431 additions
and
0 deletions
+431
-0
README.rst
README.rst
+0
-0
format.cc
format.cc
+184
-0
format.h
format.h
+247
-0
No files found.
README.
md
→
README.
rst
View file @
b076df4f
File moved
format.cc
0 → 100644
View file @
b076df4f
/*
Small, safe and fast printf-like formatting library for C++
Author: Victor Zverovich
*/
#include "format.h"
#include <cassert>
#include <cstring>
#include <algorithm>
using
std
::
size_t
;
template
<
typename
T
>
void
fmt
::
Formatter
::
FormatArg
(
const
char
*
format
,
const
T
&
arg
,
int
width
,
int
precision
)
{
size_t
offset
=
buffer_
.
size
();
buffer_
.
resize
(
buffer_
.
capacity
());
for
(;;)
{
size_t
size
=
buffer_
.
size
()
-
offset
;
int
n
=
0
;
if
(
width
<
0
)
{
n
=
precision
<
0
?
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
arg
)
:
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
precision
,
arg
);
}
else
{
n
=
precision
<
0
?
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
width
,
arg
)
:
snprintf
(
&
buffer_
[
offset
],
size
,
format
,
width
,
precision
,
arg
);
}
if
(
n
>=
0
&&
offset
+
n
<
buffer_
.
size
())
{
buffer_
.
resize
(
offset
+
n
);
return
;
}
buffer_
.
resize
(
n
>=
0
?
offset
+
n
+
1
:
2
*
buffer_
.
size
());
}
}
void
fmt
::
Formatter
::
Format
()
{
buffer_
.
reserve
(
500
);
const
char
*
start
=
format_
;
const
char
*
s
=
start
;
for
(;
*
s
;
++
s
)
{
if
(
*
s
!=
'{'
)
continue
;
buffer_
.
insert
(
buffer_
.
end
(),
start
,
s
);
++
s
;
// Parse argument index.
unsigned
arg_index
=
0
;
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
do
{
arg_index
=
arg_index
*
10
+
(
*
s
++
-
'0'
);
}
while
(
'0'
<=
*
s
&&
*
s
<=
'9'
);
}
else
{
throw
FormatError
(
"missing argument index in format string"
);
}
// TODO: check if argument index is correct
char
arg_format
[
8
];
// longest format: %+0*.*ld
char
*
arg_format_ptr
=
arg_format
;
*
arg_format_ptr
++
=
'%'
;
char
type
=
0
;
int
width
=
-
1
;
int
precision
=
-
1
;
if
(
*
s
==
':'
)
{
++
s
;
if
(
*
s
==
'+'
)
*
arg_format_ptr
++
=
*
s
++
;
if
(
*
s
==
'0'
)
*
arg_format_ptr
++
=
*
s
++
;
// Parse width.
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
*
arg_format_ptr
++
=
'*'
;
width
=
0
;
do
{
width
=
width
*
10
+
(
*
s
++
-
'0'
);
}
while
(
'0'
<=
*
s
&&
*
s
<=
'9'
);
}
// Parse precision.
if
(
*
s
==
'.'
)
{
*
arg_format_ptr
++
=
'.'
;
*
arg_format_ptr
++
=
'*'
;
++
s
;
precision
=
0
;
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
do
{
precision
=
precision
*
10
+
(
*
s
++
-
'0'
);
}
while
(
'0'
<=
*
s
&&
*
s
<=
'9'
);
}
else
{
// TODO: error
}
}
// Parse type.
if
(
*
s
==
'f'
||
*
s
==
'g'
)
type
=
*
s
++
;
// TODO: check if the type matches
}
if
(
*
s
++
!=
'}'
)
throw
FormatError
(
"single '{' encountered in format string"
);
start
=
s
;
// Format argument.
Arg
&
arg
=
args_
[
arg_index
];
switch
(
arg
.
type
)
{
case
CHAR
:
if
(
width
==
-
1
&&
precision
==
-
1
)
{
buffer_
.
push_back
(
arg
.
int_value
);
break
;
}
*
arg_format_ptr
++
=
'c'
;
*
arg_format_ptr
=
'\0'
;
FormatArg
(
arg_format
,
arg
.
int_value
,
width
,
precision
);
break
;
case
INT
:
*
arg_format_ptr
++
=
'd'
;
*
arg_format_ptr
=
'\0'
;
FormatArg
(
arg_format
,
arg
.
int_value
,
width
,
precision
);
break
;
case
UINT
:
*
arg_format_ptr
++
=
'd'
;
*
arg_format_ptr
=
'\0'
;
FormatArg
(
arg_format
,
arg
.
uint_value
,
width
,
precision
);
break
;
case
LONG
:
*
arg_format_ptr
++
=
'l'
;
*
arg_format_ptr
++
=
'd'
;
*
arg_format_ptr
=
'\0'
;
FormatArg
(
arg_format
,
arg
.
long_value
,
width
,
precision
);
break
;
case
ULONG
:
*
arg_format_ptr
++
=
'l'
;
*
arg_format_ptr
++
=
'd'
;
*
arg_format_ptr
=
'\0'
;
FormatArg
(
arg_format
,
arg
.
ulong_value
,
width
,
precision
);
break
;
case
DOUBLE
:
*
arg_format_ptr
++
=
type
?
type
:
'g'
;
*
arg_format_ptr
=
'\0'
;
FormatArg
(
arg_format
,
arg
.
double_value
,
width
,
precision
);
break
;
case
LONG_DOUBLE
:
*
arg_format_ptr
++
=
'l'
;
*
arg_format_ptr
++
=
'g'
;
*
arg_format_ptr
=
'\0'
;
FormatArg
(
arg_format
,
arg
.
long_double_value
,
width
,
precision
);
break
;
case
STRING
:
if
(
width
==
-
1
&&
precision
==
-
1
)
{
const
char
*
str
=
arg
.
string_value
;
buffer_
.
insert
(
buffer_
.
end
(),
str
,
str
+
std
::
strlen
(
str
));
break
;
}
*
arg_format_ptr
++
=
's'
;
*
arg_format_ptr
=
'\0'
;
FormatArg
(
arg_format
,
arg
.
string_value
,
width
,
precision
);
break
;
case
WSTRING
:
*
arg_format_ptr
++
=
'l'
;
*
arg_format_ptr
++
=
's'
;
*
arg_format_ptr
=
'\0'
;
FormatArg
(
arg_format
,
arg
.
wstring_value
,
width
,
precision
);
break
;
case
POINTER
:
*
arg_format_ptr
++
=
'p'
;
*
arg_format_ptr
=
'\0'
;
FormatArg
(
arg_format
,
arg
.
pointer_value
,
width
,
precision
);
break
;
default:
assert
(
false
);
break
;
}
}
buffer_
.
insert
(
buffer_
.
end
(),
start
,
s
+
1
);
}
fmt
::
ArgFormatter
::~
ArgFormatter
()
{
if
(
!
formatter_
)
return
;
FinishFormatting
();
}
format.h
0 → 100644
View file @
b076df4f
/*
Small, safe and fast printf-like formatting library for C++
Author: Victor Zverovich
*/
#ifndef FORMAT_H_
#define FORMAT_H_
#include <cstddef>
#include <cstdio>
#include <stdexcept>
#include <string>
#include <vector>
namespace
format
{
class
FormatError
:
public
std
::
runtime_error
{
public:
FormatError
(
const
std
::
string
&
message
)
:
std
::
runtime_error
(
message
)
{}
};
class
ArgFormatter
;
template
<
typename
Callback
>
class
ArgFormatterWithCallback
;
// A sprintf-like formatter that automatically allocates enough storage to
// fit all the output.
class
Formatter
{
private:
std
::
vector
<
char
>
buffer_
;
enum
Type
{
CHAR
,
INT
,
UINT
,
LONG
,
ULONG
,
DOUBLE
,
LONG_DOUBLE
,
STRING
,
WSTRING
,
POINTER
};
struct
Arg
{
Type
type
;
union
{
int
int_value
;
unsigned
uint_value
;
double
double_value
;
long
long_value
;
unsigned
long
ulong_value
;
long
double
long_double_value
;
const
char
*
string_value
;
const
wchar_t
*
wstring_value
;
const
void
*
pointer_value
;
};
explicit
Arg
(
char
value
)
:
type
(
CHAR
),
int_value
(
value
)
{}
explicit
Arg
(
int
value
)
:
type
(
INT
),
int_value
(
value
)
{}
explicit
Arg
(
unsigned
value
)
:
type
(
UINT
),
uint_value
(
value
)
{}
explicit
Arg
(
long
value
)
:
type
(
LONG
),
long_value
(
value
)
{}
explicit
Arg
(
unsigned
long
value
)
:
type
(
ULONG
),
ulong_value
(
value
)
{}
explicit
Arg
(
double
value
)
:
type
(
DOUBLE
),
double_value
(
value
)
{}
explicit
Arg
(
long
double
value
)
:
type
(
LONG_DOUBLE
),
long_double_value
(
value
)
{}
explicit
Arg
(
const
char
*
value
)
:
type
(
STRING
),
string_value
(
value
)
{}
explicit
Arg
(
const
wchar_t
*
value
)
:
type
(
WSTRING
),
wstring_value
(
value
)
{}
explicit
Arg
(
const
void
*
value
)
:
type
(
POINTER
),
pointer_value
(
value
)
{}
};
std
::
vector
<
Arg
>
args_
;
// Pointer to the part of the format string that hasn't been written yet.
const
char
*
format_
;
friend
class
ArgFormatter
;
void
Add
(
const
Arg
&
arg
)
{
if
(
args_
.
empty
())
args_
.
reserve
(
10
);
args_
.
push_back
(
arg
);
}
template
<
typename
T
>
void
FormatArg
(
const
char
*
format
,
const
T
&
arg
,
int
width
,
int
precision
);
void
Format
();
public:
Formatter
()
:
format_
(
0
)
{}
ArgFormatter
operator
()(
const
char
*
format
);
template
<
typename
Callback
>
ArgFormatterWithCallback
<
Callback
>
FormatWithCallback
(
const
char
*
format
);
const
char
*
c_str
()
const
{
return
&
buffer_
[
0
];
}
std
::
size_t
size
()
const
{
return
buffer_
.
size
()
-
1
;
}
};
class
ArgFormatter
{
private:
friend
class
Formatter
;
protected:
mutable
Formatter
*
formatter_
;
ArgFormatter
(
const
ArgFormatter
&
other
)
:
formatter_
(
other
.
formatter_
)
{
other
.
formatter_
=
0
;
}
ArgFormatter
&
operator
=
(
const
ArgFormatter
&
other
)
{
formatter_
=
other
.
formatter_
;
other
.
formatter_
=
0
;
return
*
this
;
}
Formatter
*
FinishFormatting
()
const
{
Formatter
*
f
=
formatter_
;
if
(
f
)
{
formatter_
=
0
;
f
->
Format
();
}
return
f
;
}
public:
explicit
ArgFormatter
(
Formatter
&
f
)
:
formatter_
(
&
f
)
{}
~
ArgFormatter
();
friend
const
char
*
c_str
(
const
ArgFormatter
&
af
)
{
return
af
.
FinishFormatting
()
->
c_str
();
}
friend
std
::
string
str
(
const
ArgFormatter
&
af
)
{
return
af
.
FinishFormatting
()
->
c_str
();
}
ArgFormatter
&
operator
<<
(
char
value
)
{
formatter_
->
Add
(
Formatter
::
Arg
(
value
));
return
*
this
;
}
ArgFormatter
&
operator
<<
(
int
value
)
{
formatter_
->
Add
(
Formatter
::
Arg
(
value
));
return
*
this
;
}
ArgFormatter
&
operator
<<
(
unsigned
value
)
{
formatter_
->
Add
(
Formatter
::
Arg
(
value
));
return
*
this
;
}
ArgFormatter
&
operator
<<
(
long
value
)
{
formatter_
->
Add
(
Formatter
::
Arg
(
value
));
return
*
this
;
}
ArgFormatter
&
operator
<<
(
unsigned
long
value
)
{
formatter_
->
Add
(
Formatter
::
Arg
(
value
));
return
*
this
;
}
ArgFormatter
&
operator
<<
(
double
value
)
{
formatter_
->
Add
(
Formatter
::
Arg
(
value
));
return
*
this
;
}
ArgFormatter
&
operator
<<
(
long
double
value
)
{
formatter_
->
Add
(
Formatter
::
Arg
(
value
));
return
*
this
;
}
ArgFormatter
&
operator
<<
(
const
char
*
value
)
{
formatter_
->
Add
(
Formatter
::
Arg
(
value
));
return
*
this
;
}
ArgFormatter
&
operator
<<
(
const
void
*
value
)
{
formatter_
->
Add
(
Formatter
::
Arg
(
value
));
return
*
this
;
}
// This method is not implemented intentionally to disallow output of
// arbitrary pointers. If you want to output a pointer cast it to void*.
template
<
typename
T
>
ArgFormatter
&
operator
<<
(
const
T
*
value
);
};
template
<
typename
Callback
>
class
ArgFormatterWithCallback
:
public
ArgFormatter
{
public:
explicit
ArgFormatterWithCallback
(
Formatter
&
f
)
:
ArgFormatter
(
f
)
{}
~
ArgFormatterWithCallback
()
{
if
(
!
formatter_
)
return
;
Callback
callback
;
callback
(
*
formatter_
);
}
};
inline
ArgFormatter
Formatter
::
operator
()(
const
char
*
format
)
{
format_
=
format
;
return
ArgFormatter
(
*
this
);
}
template
<
typename
Callback
>
ArgFormatterWithCallback
<
Callback
>
Formatter
::
FormatWithCallback
(
const
char
*
format
)
{
format_
=
format
;
return
ArgFormatterWithCallback
<
Callback
>
(
*
this
);
}
class
Format
:
public
ArgFormatter
{
private:
Formatter
formatter_
;
// Do not implement.
Format
(
const
Format
&
);
Format
&
operator
=
(
const
Format
&
);
public:
explicit
Format
(
const
char
*
format
)
:
ArgFormatter
(
formatter_
)
{
ArgFormatter
::
operator
=
(
formatter_
(
format
));
}
~
Format
()
{
FinishFormatting
();
}
};
class
Print
:
public
ArgFormatter
{
private:
Formatter
formatter_
;
// Do not implement.
Print
(
const
Print
&
);
Print
&
operator
=
(
const
Print
&
);
public:
explicit
Print
(
const
char
*
format
)
:
ArgFormatter
(
formatter_
)
{
ArgFormatter
::
operator
=
(
formatter_
(
format
));
}
~
Print
()
{
FinishFormatting
();
std
::
fwrite
(
formatter_
.
c_str
(),
1
,
formatter_
.
size
(),
stdout
);
}
};
}
namespace
fmt
=
format
;
#endif // FORMAT_H_
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