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
f2ee9881
Commit
f2ee9881
authored
Nov 14, 2018
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve locale support
parent
1385050e
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
140 additions
and
64 deletions
+140
-64
CMakeLists.txt
CMakeLists.txt
+2
-2
include/fmt/core.h
include/fmt/core.h
+25
-4
include/fmt/format-inl.h
include/fmt/format-inl.h
+15
-16
include/fmt/format.h
include/fmt/format.h
+22
-26
include/fmt/locale.h
include/fmt/locale.h
+47
-0
include/fmt/ostream.h
include/fmt/ostream.h
+1
-1
include/fmt/printf.h
include/fmt/printf.h
+2
-1
src/format.cc
src/format.cc
+3
-2
test/CMakeLists.txt
test/CMakeLists.txt
+1
-0
test/format-test.cc
test/format-test.cc
+1
-12
test/locale-test.cc
test/locale-test.cc
+21
-0
No files found.
CMakeLists.txt
View file @
f2ee9881
...
...
@@ -138,8 +138,8 @@ function(add_headers VAR)
endfunction
()
# Define the fmt library, its includes and the needed defines.
add_headers
(
FMT_HEADERS color.h core.h format.h format-inl.h
ostream.h printf
.h
time.h ranges.h
)
add_headers
(
FMT_HEADERS color.h core.h format.h format-inl.h
locale.h ostream
.h
printf.h
time.h ranges.h
)
set
(
FMT_SOURCES src/format.cc
)
if
(
HAVE_OPEN
)
add_headers
(
FMT_HEADERS posix.h
)
...
...
include/fmt/core.h
View file @
f2ee9881
...
...
@@ -960,6 +960,22 @@ class arg_map {
}
};
// A type-erased reference to an std::locale to avoid heavy <locale> include.
class
locale_ref
{
private:
const
void
*
locale_
;
// A type-erased pointer to std::locale.
friend
class
locale
;
public:
locale_ref
()
:
locale_
(
FMT_NULL
)
{}
template
<
typename
Locale
>
explicit
locale_ref
(
const
Locale
&
loc
);
template
<
typename
Locale
>
Locale
get
()
const
;
};
template
<
typename
OutputIt
,
typename
Context
,
typename
Char
>
class
context_base
{
public:
...
...
@@ -969,14 +985,16 @@ class context_base {
basic_parse_context
<
Char
>
parse_context_
;
iterator
out_
;
basic_format_args
<
Context
>
args_
;
locale_ref
loc_
;
protected:
typedef
Char
char_type
;
typedef
basic_format_arg
<
Context
>
format_arg
;
context_base
(
OutputIt
out
,
basic_string_view
<
char_type
>
format_str
,
basic_format_args
<
Context
>
ctx_args
)
:
parse_context_
(
format_str
),
out_
(
out
),
args_
(
ctx_args
)
{}
basic_format_args
<
Context
>
ctx_args
,
locale_ref
loc
=
locale_ref
())
:
parse_context_
(
format_str
),
out_
(
out
),
args_
(
ctx_args
),
loc_
(
loc
)
{}
// Returns the argument with specified index.
format_arg
do_get_arg
(
unsigned
arg_id
)
{
...
...
@@ -1009,6 +1027,8 @@ class context_base {
// Advances the begin iterator to ``it``.
void
advance_to
(
iterator
it
)
{
out_
=
it
;
}
locale_ref
locale
()
{
return
loc_
;
}
};
template
<
typename
Context
,
typename
T
>
...
...
@@ -1078,8 +1098,9 @@ class basic_format_context :
stored in the object so make sure they have appropriate lifetimes.
*/
basic_format_context
(
OutputIt
out
,
basic_string_view
<
char_type
>
format_str
,
basic_format_args
<
basic_format_context
>
ctx_args
)
:
base
(
out
,
format_str
,
ctx_args
)
{}
basic_format_args
<
basic_format_context
>
ctx_args
,
internal
::
locale_ref
loc
=
internal
::
locale_ref
())
:
base
(
out
,
format_str
,
ctx_args
,
loc
)
{}
format_arg
next_arg
()
{
return
this
->
do_get_arg
(
this
->
parse_context
().
next_arg_id
());
...
...
include/fmt/format-inl.h
View file @
f2ee9881
...
...
@@ -203,25 +203,28 @@ FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
}
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
class
locale
{
private:
std
::
locale
locale_
;
namespace
internal
{
public:
explicit
locale
(
std
::
locale
loc
=
std
::
locale
())
:
locale_
(
loc
)
{}
std
::
locale
get
()
{
return
locale_
;
}
};
template
<
typename
Locale
>
locale_ref
::
locale_ref
(
const
Locale
&
loc
)
:
locale_
(
&
loc
)
{
static_assert
(
std
::
is_same
<
Locale
,
std
::
locale
>::
value
,
""
);
}
template
<
typename
Locale
>
Locale
locale_ref
::
get
()
const
{
static_assert
(
std
::
is_same
<
Locale
,
std
::
locale
>::
value
,
""
);
return
locale_
?
*
static_cast
<
const
std
::
locale
*>
(
locale_
)
:
std
::
locale
();
}
namespace
internal
{
template
<
typename
Char
>
FMT_FUNC
Char
thousands_sep_impl
(
locale_
provider
*
lp
)
{
std
::
locale
loc
=
lp
?
lp
->
locale
().
get
()
:
std
::
locale
();
return
std
::
use_facet
<
std
::
numpunct
<
Char
>>
(
loc
).
thousands_sep
();
FMT_FUNC
Char
thousands_sep_impl
(
locale_
ref
loc
)
{
return
std
::
use_facet
<
std
::
numpunct
<
Char
>
>
(
loc
.
get
<
std
::
locale
>
()
).
thousands_sep
();
}
}
#else
template
<
typename
Char
>
FMT_FUNC
Char
internal
::
thousands_sep
(
locale_
provider
*
lp
)
{
FMT_FUNC
Char
internal
::
thousands_sep
(
locale_
ref
)
{
return
FMT_STATIC_THOUSANDS_SEPARATOR
;
}
#endif
...
...
@@ -959,10 +962,6 @@ FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
vprint
(
stdout
,
format_str
,
args
);
}
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
FMT_FUNC
locale
locale_provider
::
locale
()
{
return
fmt
::
locale
();
}
#endif
FMT_END_NAMESPACE
#ifdef _MSC_VER
...
...
include/fmt/format.h
View file @
f2ee9881
...
...
@@ -422,16 +422,6 @@ inline u8string_view operator"" _u(const char *s, std::size_t n) {
}
#endif
// A wrapper around std::locale used to reduce compile times since <locale>
// is very heavy.
class
locale
;
class
locale_provider
{
public:
virtual
~
locale_provider
()
{}
virtual
fmt
::
locale
locale
();
};
// The number of characters to store in the basic_memory_buffer object itself
// to avoid dynamic memory allocation.
enum
{
inline_buffer_size
=
500
};
...
...
@@ -1034,16 +1024,16 @@ class add_thousands_sep {
};
template
<
typename
Char
>
FMT_API
Char
thousands_sep_impl
(
locale_
provider
*
lp
);
FMT_API
Char
thousands_sep_impl
(
locale_
ref
loc
);
template
<
typename
Char
>
inline
Char
thousands_sep
(
locale_
provider
*
lp
)
{
return
Char
(
thousands_sep_impl
<
char
>
(
l
p
));
inline
Char
thousands_sep
(
locale_
ref
loc
)
{
return
Char
(
thousands_sep_impl
<
char
>
(
l
oc
));
}
template
<
>
inline
wchar_t
thousands_sep
(
locale_
provider
*
lp
)
{
return
thousands_sep_impl
<
wchar_t
>
(
l
p
);
inline
wchar_t
thousands_sep
(
locale_
ref
loc
)
{
return
thousands_sep_impl
<
wchar_t
>
(
l
oc
);
}
// Formats a decimal unsigned integer value writing into buffer.
...
...
@@ -1449,7 +1439,8 @@ class arg_formatter_base {
}
public:
arg_formatter_base
(
Range
r
,
format_specs
*
s
)
:
writer_
(
r
),
specs_
(
s
)
{}
arg_formatter_base
(
Range
r
,
format_specs
*
s
,
locale_ref
loc
)
:
writer_
(
r
,
loc
),
specs_
(
s
)
{}
iterator
operator
()(
monostate
)
{
FMT_ASSERT
(
false
,
"invalid argument type"
);
...
...
@@ -2320,7 +2311,7 @@ class arg_formatter:
\endrst
*/
explicit
arg_formatter
(
context_type
&
ctx
,
format_specs
*
spec
=
FMT_NULL
)
:
base
(
Range
(
ctx
.
out
()),
spec
),
ctx_
(
ctx
)
{}
:
base
(
Range
(
ctx
.
out
()),
spec
,
ctx
.
locale
()
),
ctx_
(
ctx
)
{}
// Deprecated.
arg_formatter
(
context_type
&
ctx
,
format_specs
&
spec
)
...
...
@@ -2408,7 +2399,7 @@ class basic_writer {
private:
iterator
out_
;
// Output iterator.
std
::
unique_ptr
<
locale_provider
>
locale_
;
internal
::
locale_ref
locale_
;
iterator
out
()
const
{
return
out_
;
}
...
...
@@ -2608,7 +2599,7 @@ class basic_writer {
void
on_num
()
{
unsigned
num_digits
=
internal
::
count_digits
(
abs_value
);
char_type
sep
=
internal
::
thousands_sep
<
char_type
>
(
writer
.
locale_
.
get
()
);
char_type
sep
=
internal
::
thousands_sep
<
char_type
>
(
writer
.
locale_
);
unsigned
size
=
num_digits
+
SEP_SIZE
*
((
num_digits
-
1
)
/
3
);
writer
.
write_int
(
size
,
get_prefix
(),
spec
,
num_writer
{
abs_value
,
size
,
sep
});
...
...
@@ -2698,7 +2689,9 @@ class basic_writer {
public:
/** Constructs a ``basic_writer`` object. */
explicit
basic_writer
(
Range
out
)
:
out_
(
out
.
begin
())
{}
explicit
basic_writer
(
Range
out
,
internal
::
locale_ref
loc
=
internal
::
locale_ref
())
:
out_
(
out
.
begin
()),
locale_
(
loc
)
{}
void
write
(
int
value
)
{
write_decimal
(
value
);
}
void
write
(
long
value
)
{
write_decimal
(
value
);
}
...
...
@@ -3226,8 +3219,9 @@ struct format_handler : internal::error_handler {
typedef
typename
ArgFormatter
::
range
range
;
format_handler
(
range
r
,
basic_string_view
<
Char
>
str
,
basic_format_args
<
Context
>
format_args
)
:
context
(
r
.
begin
(),
str
,
format_args
)
{}
basic_format_args
<
Context
>
format_args
,
internal
::
locale_ref
loc
)
:
context
(
r
.
begin
(),
str
,
format_args
,
loc
)
{}
void
on_text
(
const
Char
*
begin
,
const
Char
*
end
)
{
auto
size
=
internal
::
to_unsigned
(
end
-
begin
);
...
...
@@ -3277,10 +3271,12 @@ struct format_handler : internal::error_handler {
/** Formats arguments and writes the output to the range. */
template
<
typename
ArgFormatter
,
typename
Char
,
typename
Context
>
typename
Context
::
iterator
vformat_to
(
typename
ArgFormatter
::
range
out
,
typename
Context
::
iterator
vformat_to
(
typename
ArgFormatter
::
range
out
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
Context
>
args
)
{
format_handler
<
ArgFormatter
,
Char
,
Context
>
h
(
out
,
format_str
,
args
);
basic_format_args
<
Context
>
args
,
internal
::
locale_ref
loc
=
internal
::
locale_ref
())
{
format_handler
<
ArgFormatter
,
Char
,
Context
>
h
(
out
,
format_str
,
args
,
loc
);
internal
::
parse_format_string
<
false
>
(
format_str
,
h
);
return
h
.
context
.
out
();
}
...
...
include/fmt/locale.h
0 → 100644
View file @
f2ee9881
// Formatting library for C++ - std::locale support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_LOCALE_H_
#define FMT_LOCALE_H_
#include "format.h"
#include <locale>
FMT_BEGIN_NAMESPACE
namespace
internal
{
template
<
typename
Char
>
typename
buffer_context
<
Char
>::
type
::
iterator
vformat_to
(
const
std
::
locale
&
loc
,
basic_buffer
<
Char
>
&
buf
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
typename
buffer_context
<
Char
>::
type
>
args
)
{
typedef
back_insert_range
<
basic_buffer
<
Char
>
>
range
;
return
vformat_to
<
arg_formatter
<
range
>>
(
buf
,
to_string_view
(
format_str
),
args
,
internal
::
locale_ref
(
loc
));
}
template
<
typename
Char
>
std
::
basic_string
<
Char
>
vformat
(
const
std
::
locale
&
loc
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
typename
buffer_context
<
Char
>::
type
>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
internal
::
vformat_to
(
loc
,
buffer
,
format_str
,
args
);
return
fmt
::
to_string
(
buffer
);
}
}
template
<
typename
S
,
typename
...
Args
>
inline
std
::
basic_string
<
FMT_CHAR
(
S
)
>
format
(
const
std
::
locale
&
loc
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
return
internal
::
vformat
(
loc
,
to_string_view
(
format_str
),
*
internal
::
checked_args
<
S
,
Args
...
>
(
format_str
,
args
...));
}
FMT_END_NAMESPACE
#endif // FMT_LOCALE_H_
include/fmt/ostream.h
View file @
f2ee9881
// Formatting library for C++ - std::ostream support
//
// Copyright (c) 2012 -
2016
, Victor Zverovich
// Copyright (c) 2012 -
present
, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
...
...
include/fmt/printf.h
View file @
f2ee9881
...
...
@@ -243,7 +243,8 @@ class printf_arg_formatter:
*/
printf_arg_formatter
(
internal
::
basic_buffer
<
char_type
>
&
buffer
,
format_specs
&
spec
,
context_type
&
ctx
)
:
base
(
back_insert_range
<
internal
::
basic_buffer
<
char_type
>>
(
buffer
),
&
spec
),
:
base
(
back_insert_range
<
internal
::
basic_buffer
<
char_type
>>
(
buffer
),
&
spec
,
ctx
.
locale
()),
context_
(
ctx
)
{}
template
<
typename
T
>
...
...
src/format.cc
View file @
f2ee9881
...
...
@@ -9,10 +9,11 @@
FMT_BEGIN_NAMESPACE
template
struct
internal
::
basic_data
<
void
>;
template
internal
::
locale_ref
::
locale_ref
(
const
std
::
locale
&
loc
);
// Explicit instantiations for char.
template
FMT_API
char
internal
::
thousands_sep_impl
(
locale_
provider
*
lp
);
template
FMT_API
char
internal
::
thousands_sep_impl
(
locale_
ref
);
template
void
internal
::
basic_buffer
<
char
>
::
append
(
const
char
*
,
const
char
*
);
...
...
@@ -38,7 +39,7 @@ template FMT_API void internal::sprintf_format(
// Explicit instantiations for wchar_t.
template
FMT_API
wchar_t
internal
::
thousands_sep_impl
(
locale_
provider
*
);
template
FMT_API
wchar_t
internal
::
thousands_sep_impl
(
locale_
ref
);
template
void
internal
::
basic_buffer
<
wchar_t
>
::
append
(
const
wchar_t
*
,
const
wchar_t
*
);
...
...
test/CMakeLists.txt
View file @
f2ee9881
...
...
@@ -89,6 +89,7 @@ add_fmt_test(core-test)
add_fmt_test
(
gtest-extra-test
)
add_fmt_test
(
format-test mock-allocator.h
)
add_fmt_test
(
format-impl-test
)
add_fmt_test
(
locale-test
)
add_fmt_test
(
ostream-test
)
add_fmt_test
(
printf-test
)
add_fmt_test
(
time-test
)
...
...
test/format-test.cc
View file @
f2ee9881
...
...
@@ -603,17 +603,6 @@ TEST(StringViewTest, Ctor) {
EXPECT_EQ
(
4u
,
string_view
(
std
::
string
(
"defg"
)).
size
());
}
// GCC 4.6 doesn't have std::is_copy_*.
#if FMT_GCC_VERSION && FMT_GCC_VERSION >= 407
TEST
(
WriterTest
,
NotCopyConstructible
)
{
EXPECT_FALSE
(
std
::
is_copy_constructible
<
fmt
::
writer
>::
value
);
}
TEST
(
WriterTest
,
NotCopyAssignable
)
{
EXPECT_FALSE
(
std
::
is_copy_assignable
<
fmt
::
writer
>::
value
);
}
#endif
TEST
(
WriterTest
,
Data
)
{
memory_buffer
buf
;
fmt
::
writer
w
(
buf
);
...
...
@@ -1947,7 +1936,7 @@ class mock_arg_formatter:
typedef
buffer_range
range
;
mock_arg_formatter
(
fmt
::
format_context
&
ctx
,
fmt
::
format_specs
*
s
=
FMT_NULL
)
:
base
(
fmt
::
internal
::
get_container
(
ctx
.
out
()),
s
)
{
:
base
(
fmt
::
internal
::
get_container
(
ctx
.
out
()),
s
,
ctx
.
locale
()
)
{
EXPECT_CALL
(
*
this
,
call
(
42
));
}
...
...
test/locale-test.cc
0 → 100644
View file @
f2ee9881
// Formatting library for C++ - core tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/locale.h"
#include "gmock.h"
struct
numpunct
:
std
::
numpunct
<
char
>
{
protected:
char
do_thousands_sep
()
const
FMT_OVERRIDE
{
return
'~'
;
}
};
TEST
(
LocaleTest
,
Format
)
{
std
::
locale
loc
;
EXPECT_EQ
(
"1~234~567"
,
fmt
::
format
(
std
::
locale
(
loc
,
new
numpunct
()),
"{:n}"
,
1234567
));
EXPECT_EQ
(
"1,234,567"
,
fmt
::
format
(
loc
,
"{:n}"
,
1234567
));
}
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