Decouple <locale> for better compile times

This commit is contained in:
Victor Zverovich 2017-12-03 09:18:06 -08:00
parent 81bd9e8ea3
commit 7f351dec27
5 changed files with 71 additions and 8 deletions

View File

@ -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)

View File

@ -26,6 +26,7 @@
*/
#include "fmt/format.h"
#include "fmt/locale.h"
#include <string.h>
@ -218,6 +219,12 @@ void report_error(FormatFunc func, int error_code,
}
} // namespace
template <typename Char>
FMT_FUNC Char internal::thousands_sep(const basic_buffer<Char>& buf) {
return std::use_facet<std::numpunct<Char>>(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<void>;
// Explicit instantiations for char.
template locale basic_buffer<char>::locale() const;
template char internal::thousands_sep(const basic_buffer<char>& buf);
template void basic_fixed_buffer<char>::grow(std::size_t);
template void internal::arg_map<context>::init(const format_args &args);
@ -450,6 +461,10 @@ template int internal::char_traits<char>::format_float(
// Explicit instantiations for wchar_t.
template locale basic_buffer<wchar_t>::locale() const;
template wchar_t internal::thousands_sep(const basic_buffer<wchar_t>& buf);
template class basic_context<wchar_t>;
template void basic_fixed_buffer<wchar_t>::grow(std::size_t);

View File

@ -34,7 +34,6 @@
#include <cstdio>
#include <cstring>
#include <limits>
#include <locale>
#include <memory>
#include <stdexcept>
#include <string>
@ -491,6 +490,10 @@ struct error_handler {
};
} // namespace internal
// A wrapper around std::locale used to reduce compile times since <locale>
// 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<char> buffer;
@ -979,6 +982,9 @@ class add_thousands_sep {
}
};
template <typename Char>
Char thousands_sep(const basic_buffer<Char>& 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<Char>::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<std::numpunct<Char>>(loc).thousands_sep();
Char thousands_sep = internal::thousands_sep(writer.buffer_);
fmt::basic_string_view<Char> sep(&thousands_sep, 1);
unsigned size = static_cast<unsigned>(
num_digits + sep.size() * ((num_digits - 1) / 3));

43
include/fmt/locale.h Normal file
View File

@ -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 <locale>
namespace fmt {
class locale {
private:
std::locale locale_;
public:
explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
std::locale get() { return locale_; }
};
template <typename T>
locale basic_buffer<T>::locale() const { return fmt::locale(); }
}

View File

@ -37,6 +37,7 @@
# include <type_traits>
#endif
#include "fmt/locale.h"
#include "gmock/gmock.h"
#include "gtest-extra.h"
#include "mock-allocator.h"