diff --git a/include/fmt/CMakeLists.txt b/include/fmt/CMakeLists.txt index ccde97ed..d53a3ae5 100644 --- a/include/fmt/CMakeLists.txt +++ b/include/fmt/CMakeLists.txt @@ -1,7 +1,7 @@ # Define the fmt library, its includes and the needed defines. # format.cc is added to FMT_HEADERS for the header-only configuration. -set(FMT_HEADERS format.h format.cc ostream.h ostream.cc printf.h printf.cc - string.h time.h write.h) +set(FMT_HEADERS format.h format.cc locale.h ostream.h ostream.cc printf.h + printf.cc string.h time.h write.h) if (HAVE_OPEN) set(FMT_HEADERS ${FMT_HEADERS} posix.h) set(FMT_SOURCES ${FMT_SOURCES} posix.cc) diff --git a/include/fmt/format.cc b/include/fmt/format.cc index de7589b6..272c0eae 100644 --- a/include/fmt/format.cc +++ b/include/fmt/format.cc @@ -26,6 +26,7 @@ */ #include "fmt/format.h" +#include "fmt/locale.h" #include @@ -218,6 +219,12 @@ void report_error(FormatFunc func, int error_code, } } // namespace +template +FMT_FUNC Char internal::thousands_sep(const basic_buffer& buf) { + return std::use_facet>(buf.locale().get()) + .thousands_sep(); +} + FMT_FUNC void system_error::init( int err_code, string_view format_str, format_args args) { error_code_ = err_code; @@ -330,7 +337,7 @@ FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) { } FMT_FUNC void windows_error::init( - int err_code, string_view format_str, args args) { + int err_code, string_view format_str, format_args args) { error_code_ = err_code; memory_buffer buffer; internal::format_windows_error(buffer, err_code, vformat(format_str, args)); @@ -436,6 +443,10 @@ template struct internal::basic_data; // Explicit instantiations for char. +template locale basic_buffer::locale() const; + +template char internal::thousands_sep(const basic_buffer& buf); + template void basic_fixed_buffer::grow(std::size_t); template void internal::arg_map::init(const format_args &args); @@ -450,6 +461,10 @@ template int internal::char_traits::format_float( // Explicit instantiations for wchar_t. +template locale basic_buffer::locale() const; + +template wchar_t internal::thousands_sep(const basic_buffer& buf); + template class basic_context; template void basic_fixed_buffer::grow(std::size_t); diff --git a/include/fmt/format.h b/include/fmt/format.h index b168bbce..db618a8e 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -491,6 +490,10 @@ struct error_handler { }; } // namespace internal +// A wrapper around std::locale used to reduce compile times since +// is very heavy. +class locale; + /** \rst A contiguous memory buffer with an optional growing ability. @@ -566,7 +569,7 @@ class basic_buffer { T &operator[](std::size_t index) { return ptr_[index]; } const T &operator[](std::size_t index) const { return ptr_[index]; } - virtual std::locale locale() const { return std::locale(); } + virtual fmt::locale locale() const; }; typedef basic_buffer buffer; @@ -979,6 +982,9 @@ class add_thousands_sep { } }; +template +Char thousands_sep(const basic_buffer& buf); + // Formats a decimal unsigned integer value writing into buffer. // thousands_sep is a functor that is called after writing each char to // add a thousands separator if necessary. @@ -3352,9 +3358,7 @@ void basic_writer::write_int(T value, const Spec& spec) { void on_num() { unsigned num_digits = internal::count_digits(abs_value); - std::locale loc = writer.buffer_.locale(); - Char thousands_sep = - std::use_facet>(loc).thousands_sep(); + Char thousands_sep = internal::thousands_sep(writer.buffer_); fmt::basic_string_view sep(&thousands_sep, 1); unsigned size = static_cast( num_digits + sep.size() * ((num_digits - 1) / 3)); diff --git a/include/fmt/locale.h b/include/fmt/locale.h new file mode 100644 index 00000000..6839e55a --- /dev/null +++ b/include/fmt/locale.h @@ -0,0 +1,43 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fmt/format.h" +#include + +namespace fmt { +class locale { + private: + std::locale locale_; + + public: + explicit locale(std::locale loc = std::locale()) : locale_(loc) {} + std::locale get() { return locale_; } +}; + +template +locale basic_buffer::locale() const { return fmt::locale(); } +} diff --git a/test/util-test.cc b/test/util-test.cc index 566044c3..eb41271e 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -37,6 +37,7 @@ # include #endif +#include "fmt/locale.h" #include "gmock/gmock.h" #include "gtest-extra.h" #include "mock-allocator.h"