Update coverity branch
This commit is contained in:
commit
566f393b49
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,3 +14,4 @@ CTestTestfile.cmake
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
Makefile
|
||||
run-msbuild.bat
|
||||
|
@ -12,6 +12,11 @@ endif ()
|
||||
|
||||
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
|
||||
|
||||
# Options that control generation of various targets.
|
||||
option(FMT_DOC "Generate the doc target." ON)
|
||||
option(FMT_INSTALL "Generate the install target." ON)
|
||||
option(FMT_TEST "Generate the test target." ON)
|
||||
|
||||
project(FORMAT)
|
||||
|
||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||
@ -90,7 +95,7 @@ if (BIICODE)
|
||||
endif ()
|
||||
|
||||
add_library(cppformat ${FMT_SOURCES})
|
||||
if (BUILD_SHARED_LIBS)
|
||||
if (BUILD_SHARED_LIBS AND UNIX AND NOT APPLE)
|
||||
# Fix rpmlint warning:
|
||||
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
|
||||
target_link_libraries(cppformat -Wl,--as-needed)
|
||||
@ -106,89 +111,21 @@ endif ()
|
||||
# over compile options, so the options used here only matter for testing.
|
||||
if (CPP11_FLAG AND FMT_PEDANTIC)
|
||||
set(FMT_EXTRA_COMPILE_FLAGS "${FMT_EXTRA_COMPILE_FLAGS} ${CPP11_FLAG}")
|
||||
# Test compilation with default flags.
|
||||
file(GLOB src RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test/*.cc test/*.h)
|
||||
add_library(testformat STATIC ${FMT_SOURCE_FILES} ${src})
|
||||
set(FMT_TEST_DEFAULT_FLAGS TRUE)
|
||||
endif ()
|
||||
|
||||
set_target_properties(cppformat
|
||||
PROPERTIES COMPILE_FLAGS "${FMT_EXTRA_COMPILE_FLAGS}")
|
||||
|
||||
add_subdirectory(doc)
|
||||
|
||||
include_directories(. gmock)
|
||||
|
||||
# We compile Google Test ourselves instead of using pre-compiled libraries.
|
||||
# See the Google Test FAQ "Why is it not recommended to install a
|
||||
# pre-compiled copy of Google Test (for example, into /usr/local)?"
|
||||
# at http://code.google.com/p/googletest/wiki/FAQ for more details.
|
||||
|
||||
add_library(gmock STATIC
|
||||
gmock/gmock-gtest-all.cc gmock/gmock/gmock.h
|
||||
gmock/gtest/gtest.h gmock/gtest/gtest-spi.h)
|
||||
find_package(Threads)
|
||||
if (Threads_FOUND)
|
||||
target_link_libraries(gmock ${CMAKE_THREAD_LIBS_INIT})
|
||||
else ()
|
||||
target_compile_definitions(gmock PUBLIC GTEST_HAS_PTHREAD=0)
|
||||
if (FMT_DOC)
|
||||
add_subdirectory(doc)
|
||||
endif ()
|
||||
|
||||
# Check if variadic templates are working and not affected by GCC bug 39653:
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
|
||||
check_cxx_source_compiles("
|
||||
template <class T, class ...Types>
|
||||
struct S { typedef typename S<Types...>::type type; };
|
||||
int main() {}" FMT_VARIADIC_TEMPLATES)
|
||||
|
||||
# Check if initializer lists are supported.
|
||||
check_cxx_source_compiles("
|
||||
#include <initializer_list>
|
||||
int main() {}" FMT_INITIALIZER_LIST)
|
||||
|
||||
if (NOT FMT_VARIADIC_TEMPLATES OR NOT FMT_INITIALIZER_LIST)
|
||||
add_definitions(-DGTEST_LANG_CXX11=0)
|
||||
if (FMT_TEST)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif ()
|
||||
|
||||
# This is disabled at the moment because format is compiled without -std=c++11
|
||||
# by default.
|
||||
#check_cxx_source_compiles("
|
||||
# void f() noexcept {}
|
||||
# int main(){ f(); }" FMT_BASIC_NOEXCEPT_SUPPORT)
|
||||
#if (FMT_BASIC_NOEXCEPT_SUPPORT)
|
||||
# add_definitions(-DFMT_USE_NOEXCEPT=1)
|
||||
#endif ()
|
||||
|
||||
#check_cxx_source_compiles("
|
||||
# struct C{
|
||||
# C()=delete;
|
||||
# C(const C&)=delete;
|
||||
# C& operator=(const C&)=delete;
|
||||
# };
|
||||
# int main(){}" FMT_DELETED_FUNCTIONS)
|
||||
#if (FMT_DELETED_FUNCTIONS)
|
||||
# add_definitions(-DFMT_USE_DELETED_FUNCTIONS=1)
|
||||
#endif ()
|
||||
|
||||
#check_cxx_source_compiles("
|
||||
# static_assert(true, \"\");
|
||||
# int main(){}" FMT_STATIC_ASSERT)
|
||||
#if (FMT_STATIC_ASSERT)
|
||||
# add_definitions(-DFMT_USE_STATIC_ASSERT=1)
|
||||
#endif ()
|
||||
|
||||
# Workaround a bug in implementation of variadic templates in MSVC11.
|
||||
if (MSVC)
|
||||
target_compile_definitions(gmock PUBLIC _VARIADIC_MAX=10)
|
||||
endif ()
|
||||
|
||||
# GTest doesn't detect <tuple> with clang.
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
target_compile_definitions(gmock PUBLIC GTEST_USE_OWN_TR1_TUPLE=1)
|
||||
endif ()
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 1)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 2)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||
@ -206,7 +143,8 @@ if (EXISTS .gitignore)
|
||||
string(REPLACE "*" ".*" line "${line}")
|
||||
set(ignored_files ${ignored_files} "${line}$" "${line}/")
|
||||
endforeach ()
|
||||
set(ignored_files ${ignored_files} /.git /breathe /format-benchmark sphinx/)
|
||||
set(ignored_files ${ignored_files}
|
||||
/.git /breathe /format-benchmark sphinx/ .buildinfo .doctrees)
|
||||
|
||||
set(CPACK_SOURCE_GENERATOR ZIP)
|
||||
set(CPACK_SOURCE_IGNORE_FILES ${ignored_files})
|
||||
@ -216,7 +154,9 @@ if (EXISTS .gitignore)
|
||||
endif ()
|
||||
|
||||
# Install targets.
|
||||
set(FMT_LIB_DIR lib CACHE STRING
|
||||
if (FMT_INSTALL)
|
||||
set(FMT_LIB_DIR lib CACHE STRING
|
||||
"Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.")
|
||||
install(TARGETS cppformat DESTINATION ${FMT_LIB_DIR})
|
||||
install(FILES format.h DESTINATION include/cppformat)
|
||||
install(TARGETS cppformat DESTINATION ${FMT_LIB_DIR})
|
||||
install(FILES format.h DESTINATION include/cppformat)
|
||||
endif ()
|
||||
|
@ -149,6 +149,8 @@ Projects using this library
|
||||
|
||||
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
|
||||
|
||||
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster proxy
|
||||
|
||||
* `Saddy <https://code.google.com/p/saddy/>`_:
|
||||
Small crossplatform 2D graphic engine
|
||||
|
||||
@ -157,6 +159,10 @@ Projects using this library
|
||||
|
||||
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
|
||||
|
||||
* `Stellar <https://www.stellar.org/>`_: Financial platform
|
||||
|
||||
* `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator
|
||||
|
||||
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source MMORPG framework
|
||||
|
||||
`More... <https://github.com/search?q=cppformat&type=Code>`_
|
||||
|
10
appveyor.yml
10
appveyor.yml
@ -1,14 +1,14 @@
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
environment:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
matrix:
|
||||
- BUILD: msvc
|
||||
CONFIG: Debug
|
||||
- BUILD: msvc
|
||||
CONFIG: Release
|
||||
PLATFORM: x64
|
||||
- BUILD: mingw
|
||||
CONFIG: Debug
|
||||
- BUILD: mingw
|
||||
CONFIG: Release
|
||||
|
||||
build_script:
|
||||
- python support/appveyor-build.py
|
||||
|
@ -6,4 +6,5 @@ endif ()
|
||||
|
||||
add_custom_target(doc COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py)
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/ DESTINATION share/doc/cppformat)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html
|
||||
DESTINATION share/doc/cppformat)
|
||||
|
@ -26,6 +26,8 @@ arguments in the resulting string.
|
||||
|
||||
.. doxygenfunction:: format(CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: operator""_format(const char *, std::size_t)
|
||||
|
||||
.. _print:
|
||||
|
||||
.. doxygenfunction:: print(CStringRef, ArgList)
|
||||
@ -74,6 +76,8 @@ Utilities
|
||||
|
||||
.. doxygenfunction:: fmt::arg(StringRef, const T&)
|
||||
|
||||
.. doxygenfunction:: operator""_a(const char *, std::size_t)
|
||||
|
||||
.. doxygendefine:: FMT_CAPTURE
|
||||
|
||||
.. doxygendefine:: FMT_VARIADIC
|
||||
|
63
doc/build.py
63
doc/build.py
@ -1,26 +1,22 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
# Build the documentation.
|
||||
|
||||
from __future__ import print_function
|
||||
import os, shutil, tempfile
|
||||
from subprocess import check_call, CalledProcessError, Popen, PIPE
|
||||
import errno, os, shutil, sys, tempfile
|
||||
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
def pip_install(package, commit=None):
|
||||
def pip_install(package, commit=None, **kwargs):
|
||||
"Install package using pip."
|
||||
if commit:
|
||||
cmd = ['pip', 'show', package.split('/')[1]]
|
||||
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if stdout:
|
||||
return # Already installed
|
||||
elif p.returncode != 0:
|
||||
# Old versions of pip such as the one installed on Travis don't support
|
||||
# the show command - continue installation in this case.
|
||||
# Otherwise throw CalledProcessError.
|
||||
if p.returncode > 1 and 'No command by the name pip show' not in stderr:
|
||||
raise CalledProcessError(p.returncode, cmd)
|
||||
check_version = kwargs.get('check_version', '')
|
||||
#output = check_output(['pip', 'show', package.split('/')[1]])
|
||||
#if check_version in output:
|
||||
# print('{} already installed'.format(package))
|
||||
# return
|
||||
package = 'git+git://github.com/{0}.git@{1}'.format(package, commit)
|
||||
check_call(['pip', 'install', '-q', package])
|
||||
print('Installing {}'.format(package))
|
||||
check_call(['pip', 'install', '--upgrade', package])
|
||||
|
||||
def build_docs():
|
||||
# Create virtualenv.
|
||||
@ -28,9 +24,28 @@ def build_docs():
|
||||
virtualenv_dir = 'virtualenv'
|
||||
check_call(['virtualenv', virtualenv_dir])
|
||||
activate_this_file = os.path.join(virtualenv_dir, 'bin', 'activate_this.py')
|
||||
execfile(activate_this_file, dict(__file__=activate_this_file))
|
||||
with open(activate_this_file) as f:
|
||||
exec(f.read(), dict(__file__=activate_this_file))
|
||||
# Upgrade pip because installation of sphinx with pip 1.1 available on Travis
|
||||
# is broken (see #207) and it doesn't support the show command.
|
||||
from pkg_resources import get_distribution, DistributionNotFound
|
||||
pip_version = get_distribution('pip').version
|
||||
if LooseVersion(pip_version) < LooseVersion('1.5.4'):
|
||||
print("Updating pip")
|
||||
check_call(['pip', 'install', '--upgrade', 'pip'])
|
||||
# Upgrade distribute because installation of sphinx with distribute 0.6.24
|
||||
# available on Travis is broken (see #207).
|
||||
try:
|
||||
distribute_version = get_distribution('distribute').version
|
||||
if LooseVersion(distribute_version) <= LooseVersion('0.6.24'):
|
||||
print("Updating distribute")
|
||||
check_call(['pip', 'install', '--upgrade', 'distribute'])
|
||||
except DistributionNotFound:
|
||||
pass
|
||||
# Install Sphinx and Breathe.
|
||||
pip_install('sphinx==1.3.1')
|
||||
pip_install('cppformat/sphinx',
|
||||
'12dde8afdb0a7bb5576e2656692c3478c69d8cc3',
|
||||
check_version='1.4a0.dev-20151013')
|
||||
pip_install('michaeljones/breathe',
|
||||
'511b0887293e7c6b12310bb61b3659068f48f0f4')
|
||||
# Build docs.
|
||||
@ -43,7 +58,6 @@ def build_docs():
|
||||
GENERATE_RTF = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
INPUT = {0}/format.h
|
||||
EXCLUDE_SYMBOLS = fmt::internal::*
|
||||
QUIET = YES
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
AUTOLINK_SUPPORT = NO
|
||||
@ -54,18 +68,25 @@ def build_docs():
|
||||
ALIASES += "endrst=\endverbatim"
|
||||
PREDEFINED = _WIN32=1 \
|
||||
FMT_USE_VARIADIC_TEMPLATES=1 \
|
||||
FMT_USE_RVALUE_REFERENCES=1
|
||||
FMT_USE_RVALUE_REFERENCES=1 \
|
||||
FMT_USE_USER_DEFINED_LITERALS=1
|
||||
EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str
|
||||
'''.format(os.path.dirname(doc_dir)))
|
||||
'''.format(os.path.dirname(doc_dir)).encode('UTF-8'))
|
||||
if p.returncode != 0:
|
||||
raise CalledProcessError(p.returncode, cmd)
|
||||
check_call(['sphinx-build', '-D',
|
||||
'breathe_projects.format=' + os.path.join(os.getcwd(), 'doxyxml'),
|
||||
'-b', 'html', doc_dir, 'html'])
|
||||
try:
|
||||
check_call(['lessc', '--clean-css',
|
||||
'--include-path=' + os.path.join(doc_dir, 'bootstrap'),
|
||||
os.path.join(doc_dir, 'cppformat.less'),
|
||||
'html/_static/cppformat.css'])
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
print('lessc not found; make sure that Less (http://lesscss.org/) is installed')
|
||||
sys.exit(1)
|
||||
return 'html'
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -13,11 +13,6 @@ html {
|
||||
background-color: darken(@header-bg, 10%);
|
||||
}
|
||||
|
||||
.navbar-content {
|
||||
.make-md-column-offset(2);
|
||||
.make-md-column(8);
|
||||
}
|
||||
|
||||
.jumbotron {
|
||||
#gradient > .vertical(@header-bg; darken(@header-bg, 2%); 50%; 50%);
|
||||
background-size: 100% 4px;
|
||||
@ -32,9 +27,11 @@ div.sphinxsidebar {
|
||||
}
|
||||
|
||||
// Keep content not too wide for better readability.
|
||||
.content {
|
||||
.make-md-column-offset(2);
|
||||
.make-md-column(8);
|
||||
.navbar-content, .content {
|
||||
.make-md-column-offset(1);
|
||||
.make-md-column(10);
|
||||
.make-lg-column-offset(2);
|
||||
.make-lg-column(8);
|
||||
}
|
||||
|
||||
.footer {
|
||||
|
@ -65,6 +65,34 @@ The Format API also supports positional arguments useful for localization:
|
||||
|
||||
fmt::print("I'd rather be {1} than {0}.", "right", "happy");
|
||||
|
||||
Named arguments can be created with ``fmt::arg``. This makes it easier to track
|
||||
what goes where when multiple values are being inserted:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::print("Hello, {name}! The answer is {number}. Goodbye, {name}.",
|
||||
fmt::arg("name", "World"), fmt::arg("number", 42));
|
||||
|
||||
If your compiler supports C++11 user-defined literals, the suffix ``_a`` offers
|
||||
an alternative, slightly terser syntax for named arguments:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::print("Hello, {name}! The answer is {number}. Goodbye, {name}.",
|
||||
"name"_a="World", "number"_a=42);
|
||||
|
||||
The ``_format`` suffix may be used to format string literals similar to Python:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
std::string message = "{0}{1}{0}"_format("abra", "cad");
|
||||
|
||||
Other than the placement of the format string on the left of the operator,
|
||||
``_format`` is functionally identical to ``fmt::format``. In order to use the
|
||||
literal operators, they must be made visible with the directive
|
||||
``using namespace fmt::literals;``. Note that this brings in only ``_a`` and
|
||||
``_format`` but nothing else from the ``fmt`` namespace.
|
||||
|
||||
.. _write-api:
|
||||
|
||||
Write API
|
||||
@ -128,13 +156,22 @@ compilers where it has been tested and known to work:
|
||||
|
||||
* Mac OS X with GCC 4.2.1 and Clang 4.2, 5.1.0
|
||||
|
||||
* 64-bit Windows with Visual C++ 2010 and
|
||||
`2013 <https://ci.appveyor.com/project/vitaut/cppformat>`_
|
||||
* 64-bit Windows with Visual C++ 2010, 2013 and
|
||||
`2015 <https://ci.appveyor.com/project/vitaut/cppformat>`_
|
||||
|
||||
* 32-bit Windows with Visual C++ 2010
|
||||
|
||||
Although the library uses C++11 features when available, it also works with older
|
||||
compilers and standard library implementations.
|
||||
compilers and standard library implementations. The only thing to keep in mind
|
||||
for C++98 portability:
|
||||
|
||||
* Variadic templates: minimum GCC 4.4, Clang 2.9 or VS2013. This feature allows
|
||||
the Format API to accept an unlimited number of arguments. With older compilers
|
||||
the maximum is 15.
|
||||
|
||||
* User-defined literals: minimum GCC 4.7, Clang 3.1 or VS2015. The suffixes
|
||||
``_format`` and ``_a`` are functionally equivalent to the functions
|
||||
``fmt::format`` and ``fmt::arg``.
|
||||
|
||||
The output of all formatting functions is consistent across platforms. In particular,
|
||||
formatting a floating-point infinity always gives ``inf`` while the output
|
||||
|
@ -54,6 +54,23 @@ To build a `shared library`__ set the ``BUILD_SHARED_LIBS`` CMake variable to
|
||||
|
||||
__ http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries
|
||||
|
||||
Building the documentation
|
||||
==========================
|
||||
|
||||
To build the documentation you need the following software installed on your
|
||||
system:
|
||||
|
||||
* `Python <https://www.python.org/>`_ with pip and virtualenv
|
||||
* `Doxygen <http://www.stack.nl/~dimitri/doxygen/>`_
|
||||
* `Less <http://lesscss.org/>`_ with less-plugin-clean-css
|
||||
|
||||
First generate makefiles or project files using CMake as described in
|
||||
the previous section. Then compile the ``doc`` target/project, for example::
|
||||
|
||||
make doc
|
||||
|
||||
This will generate the HTML documenation in ``doc/html``.
|
||||
|
||||
Android NDK
|
||||
===========
|
||||
|
||||
|
23
format.cc
23
format.cc
@ -523,6 +523,13 @@ class PrintfArgFormatter :
|
||||
}
|
||||
*out = static_cast<Char>(value);
|
||||
}
|
||||
|
||||
void visit_custom(Arg::CustomValue c) {
|
||||
BasicFormatter<Char> formatter(ArgList(), this->writer());
|
||||
const Char format_str[] = {'}', 0};
|
||||
const Char *format = format_str;
|
||||
c.format(&formatter, c.value, &format);
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace fmt
|
||||
@ -612,14 +619,17 @@ FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
|
||||
#if FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
|
||||
int length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), 0, 0);
|
||||
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
|
||||
if (s.size() > INT_MAX)
|
||||
FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
|
||||
int s_size = static_cast<int>(s.size());
|
||||
int length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
|
||||
if (length == 0)
|
||||
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
|
||||
buffer_.resize(length + 1);
|
||||
length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), &buffer_[0], length);
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
|
||||
if (length == 0)
|
||||
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
|
||||
buffer_[length] = 0;
|
||||
@ -633,12 +643,15 @@ FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
|
||||
}
|
||||
|
||||
FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
|
||||
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(), 0, 0, 0, 0);
|
||||
if (s.size() > INT_MAX)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
int s_size = static_cast<int>(s.size());
|
||||
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
buffer_.resize(length + 1);
|
||||
length = WideCharToMultiByte(
|
||||
CP_UTF8, 0, s.data(), s.size(), &buffer_[0], length, 0, 0);
|
||||
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
buffer_[length] = 0;
|
||||
|
148
format.h
148
format.h
@ -38,9 +38,16 @@
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#ifndef FMT_USE_IOSTREAMS
|
||||
# define FMT_USE_IOSTREAMS 1
|
||||
#endif
|
||||
|
||||
#if FMT_USE_IOSTREAMS
|
||||
# include <sstream>
|
||||
#endif
|
||||
|
||||
#if _SECURE_SCL
|
||||
# include <iterator>
|
||||
#endif
|
||||
@ -177,6 +184,16 @@ inline uint32_t clzll(uint64_t x) {
|
||||
TypeName& operator=(const TypeName&)
|
||||
#endif
|
||||
|
||||
#ifndef FMT_USE_USER_DEFINED_LITERALS
|
||||
// All compilers which support UDLs also support variadic templates. This
|
||||
// makes the fmt::literals implementation easier. However, an explicit check
|
||||
// for variadic templates is added here just in case.
|
||||
# define FMT_USE_USER_DEFINED_LITERALS \
|
||||
FMT_USE_VARIADIC_TEMPLATES && \
|
||||
(FMT_HAS_FEATURE(cxx_user_literals) || \
|
||||
(FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1900)
|
||||
#endif
|
||||
|
||||
#ifndef FMT_ASSERT
|
||||
# define FMT_ASSERT(condition, message) assert((condition) && message)
|
||||
#endif
|
||||
@ -285,7 +302,6 @@ class BasicStringRef {
|
||||
typedef BasicStringRef<char> StringRef;
|
||||
typedef BasicStringRef<wchar_t> WStringRef;
|
||||
|
||||
|
||||
/**
|
||||
\rst
|
||||
A reference to a null terminated string. It can be constructed from a C
|
||||
@ -449,9 +465,9 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
|
||||
private:
|
||||
T data_[SIZE];
|
||||
|
||||
// Free memory allocated by the buffer.
|
||||
void free() {
|
||||
if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_);
|
||||
// Deallocate memory allocated by the buffer.
|
||||
void deallocate() {
|
||||
if (this->ptr_ != data_) Allocator::deallocate(this->ptr_, this->capacity_);
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -460,7 +476,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
|
||||
public:
|
||||
explicit MemoryBuffer(const Allocator &alloc = Allocator())
|
||||
: Allocator(alloc), Buffer<T>(data_, SIZE) {}
|
||||
~MemoryBuffer() { free(); }
|
||||
~MemoryBuffer() { deallocate(); }
|
||||
|
||||
#if FMT_USE_RVALUE_REFERENCES
|
||||
private:
|
||||
@ -477,7 +493,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
|
||||
} else {
|
||||
this->ptr_ = other.ptr_;
|
||||
// Set pointer to the inline array so that delete is not called
|
||||
// when freeing.
|
||||
// when deallocating.
|
||||
other.ptr_ = other.data_;
|
||||
}
|
||||
}
|
||||
@ -489,7 +505,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
|
||||
|
||||
MemoryBuffer &operator=(MemoryBuffer &&other) {
|
||||
assert(this != &other);
|
||||
free();
|
||||
deallocate();
|
||||
move(other);
|
||||
return *this;
|
||||
}
|
||||
@ -515,7 +531,7 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
|
||||
// the buffer already uses the new storage and will deallocate it in case
|
||||
// of exception.
|
||||
if (old_ptr != data_)
|
||||
this->deallocate(old_ptr, old_capacity);
|
||||
Allocator::deallocate(old_ptr, old_capacity);
|
||||
}
|
||||
|
||||
// A fixed-size buffer.
|
||||
@ -712,24 +728,23 @@ inline unsigned count_digits(uint32_t n) {
|
||||
// Formats a decimal unsigned integer value writing into buffer.
|
||||
template <typename UInt, typename Char>
|
||||
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
|
||||
--num_digits;
|
||||
buffer += num_digits;
|
||||
while (value >= 100) {
|
||||
// Integer division is slow so do it for a group of two digits instead
|
||||
// of for every digit. The idea comes from the talk by Alexandrescu
|
||||
// "Three Optimization Tips for C++". See speed-test for a comparison.
|
||||
unsigned index = (value % 100) * 2;
|
||||
value /= 100;
|
||||
buffer[num_digits] = Data::DIGITS[index + 1];
|
||||
buffer[num_digits - 1] = Data::DIGITS[index];
|
||||
num_digits -= 2;
|
||||
*--buffer = Data::DIGITS[index + 1];
|
||||
*--buffer = Data::DIGITS[index];
|
||||
}
|
||||
if (value < 10) {
|
||||
*buffer = static_cast<char>('0' + value);
|
||||
*--buffer = static_cast<char>('0' + value);
|
||||
return;
|
||||
}
|
||||
unsigned index = static_cast<unsigned>(value * 2);
|
||||
buffer[1] = Data::DIGITS[index + 1];
|
||||
buffer[0] = Data::DIGITS[index];
|
||||
*--buffer = Data::DIGITS[index + 1];
|
||||
*--buffer = Data::DIGITS[index];
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
@ -1047,7 +1062,7 @@ struct NamedArg : Arg {
|
||||
|
||||
template <typename T>
|
||||
NamedArg(BasicStringRef<Char> argname, const T &value)
|
||||
: name(argname), Arg(MakeValue<Char>(value)) {
|
||||
: Arg(MakeValue<Char>(value)), name(argname) {
|
||||
type = static_cast<internal::Arg::Type>(MakeValue<Char>::type(value));
|
||||
}
|
||||
};
|
||||
@ -2677,17 +2692,6 @@ void print(std::FILE *f, CStringRef format_str, ArgList args);
|
||||
*/
|
||||
void print(CStringRef format_str, ArgList args);
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the stream *os*.
|
||||
|
||||
**Example**::
|
||||
|
||||
print(cerr, "Don't {}!", "panic");
|
||||
\endrst
|
||||
*/
|
||||
void print(std::ostream &os, CStringRef format_str, ArgList args);
|
||||
|
||||
template <typename Char>
|
||||
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) {
|
||||
internal::PrintfFormatter<Char>(args).format(w, format);
|
||||
@ -2708,6 +2712,12 @@ inline std::string sprintf(CStringRef format, ArgList args) {
|
||||
return w.str();
|
||||
}
|
||||
|
||||
inline std::wstring sprintf(WCStringRef format, ArgList args) {
|
||||
WMemoryWriter w;
|
||||
printf(w, format, args);
|
||||
return w.str();
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the file *f*.
|
||||
@ -2993,12 +3003,90 @@ FMT_VARIADIC(std::string, format, CStringRef)
|
||||
FMT_VARIADIC_W(std::wstring, format, WCStringRef)
|
||||
FMT_VARIADIC(void, print, CStringRef)
|
||||
FMT_VARIADIC(void, print, std::FILE *, CStringRef)
|
||||
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
|
||||
|
||||
FMT_VARIADIC(void, print_colored, Color, CStringRef)
|
||||
FMT_VARIADIC(std::string, sprintf, CStringRef)
|
||||
FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
|
||||
FMT_VARIADIC(int, printf, CStringRef)
|
||||
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
|
||||
}
|
||||
|
||||
#if FMT_USE_IOSTREAMS
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the stream *os*.
|
||||
|
||||
**Example**::
|
||||
|
||||
print(cerr, "Don't {}!", "panic");
|
||||
\endrst
|
||||
*/
|
||||
void print(std::ostream &os, CStringRef format_str, ArgList args);
|
||||
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
|
||||
#endif
|
||||
} // namespace fmt
|
||||
|
||||
#if FMT_USE_USER_DEFINED_LITERALS
|
||||
namespace fmt {
|
||||
namespace internal {
|
||||
|
||||
template <typename Char>
|
||||
struct UdlFormat {
|
||||
const Char *str;
|
||||
|
||||
template <typename... Args>
|
||||
auto operator()(Args && ... args) const
|
||||
-> decltype(format(str, std::forward<Args>(args)...)) {
|
||||
return format(str, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct UdlArg {
|
||||
const Char *str;
|
||||
|
||||
template <typename T>
|
||||
NamedArg<Char> operator=(T &&value) const {
|
||||
return {str, std::forward<T>(value)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
/**
|
||||
\rst
|
||||
C++11 literal equivalent of :func:`fmt::format`.
|
||||
|
||||
**Example**::
|
||||
|
||||
using namespace fmt::literals;
|
||||
std::string message = "The answer is {}"_format(42);
|
||||
\endrst
|
||||
*/
|
||||
inline internal::UdlFormat<char>
|
||||
operator"" _format(const char *s, std::size_t) { return {s}; }
|
||||
inline internal::UdlFormat<wchar_t>
|
||||
operator"" _format(const wchar_t *s, std::size_t) { return {s}; }
|
||||
|
||||
/**
|
||||
\rst
|
||||
C++11 literal equivalent of :func:`fmt::arg`.
|
||||
|
||||
**Example**::
|
||||
|
||||
using namespace fmt::literals;
|
||||
print("Elapsed time: {s:.2f} seconds", "s"_a=1.23);
|
||||
\endrst
|
||||
*/
|
||||
inline internal::UdlArg<char>
|
||||
operator"" _a(const char *s, std::size_t) { return {s}; }
|
||||
inline internal::UdlArg<wchar_t>
|
||||
operator"" _a(const wchar_t *s, std::size_t) { return {s}; }
|
||||
|
||||
} // inline namespace literals
|
||||
} // namespace fmt
|
||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||
|
||||
// Restore warnings.
|
||||
#if FMT_GCC_VERSION >= 406
|
||||
|
@ -5,7 +5,8 @@ import os
|
||||
from subprocess import check_call
|
||||
|
||||
build = os.environ['BUILD']
|
||||
config = os.environ['CONFIG']
|
||||
config = os.environ['CONFIGURATION']
|
||||
platform = os.environ.get('PLATFORM')
|
||||
path = os.environ['PATH']
|
||||
cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config]
|
||||
if build == 'mingw':
|
||||
@ -19,6 +20,10 @@ else:
|
||||
# Add MSBuild 14.0 to PATH as described in
|
||||
# http://help.appveyor.com/discussions/problems/2229-v140-not-found-on-vs2105rc.
|
||||
os.environ['PATH'] = r'C:\Program Files (x86)\MSBuild\14.0\Bin;' + path
|
||||
generator = 'Visual Studio 14 2015'
|
||||
if platform == 'x64':
|
||||
generator += ' Win64'
|
||||
cmake_command.append('-G' + generator)
|
||||
build_command = ['msbuild', '/m:4', '/p:Config=' + config, 'FORMAT.sln']
|
||||
test_command = ['msbuild', 'RUN_TESTS.vcxproj']
|
||||
|
||||
|
@ -1,3 +1,48 @@
|
||||
set(FMT_GMOCK_DIR ../gmock)
|
||||
|
||||
include_directories(.. ${FMT_GMOCK_DIR})
|
||||
|
||||
# We compile Google Test ourselves instead of using pre-compiled libraries.
|
||||
# See the Google Test FAQ "Why is it not recommended to install a
|
||||
# pre-compiled copy of Google Test (for example, into /usr/local)?"
|
||||
# at http://code.google.com/p/googletest/wiki/FAQ for more details.
|
||||
|
||||
add_library(gmock STATIC
|
||||
${FMT_GMOCK_DIR}/gmock-gtest-all.cc ${FMT_GMOCK_DIR}/gmock/gmock.h
|
||||
${FMT_GMOCK_DIR}/gtest/gtest.h ${FMT_GMOCK_DIR}/gtest/gtest-spi.h)
|
||||
find_package(Threads)
|
||||
if (Threads_FOUND)
|
||||
target_link_libraries(gmock ${CMAKE_THREAD_LIBS_INIT})
|
||||
else ()
|
||||
target_compile_definitions(gmock PUBLIC GTEST_HAS_PTHREAD=0)
|
||||
endif ()
|
||||
|
||||
# Check if variadic templates are working and not affected by GCC bug 39653:
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
|
||||
check_cxx_source_compiles("
|
||||
template <class T, class ...Types>
|
||||
struct S { typedef typename S<Types...>::type type; };
|
||||
int main() {}" FMT_VARIADIC_TEMPLATES)
|
||||
|
||||
# Check if initializer lists are supported.
|
||||
check_cxx_source_compiles("
|
||||
#include <initializer_list>
|
||||
int main() {}" FMT_INITIALIZER_LIST)
|
||||
|
||||
if (NOT FMT_VARIADIC_TEMPLATES OR NOT FMT_INITIALIZER_LIST)
|
||||
add_definitions(-DGTEST_LANG_CXX11=0)
|
||||
endif ()
|
||||
|
||||
# Workaround a bug in implementation of variadic templates in MSVC11.
|
||||
if (MSVC)
|
||||
target_compile_definitions(gmock PUBLIC _VARIADIC_MAX=10)
|
||||
endif ()
|
||||
|
||||
# GTest doesn't detect <tuple> with clang.
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
target_compile_definitions(gmock PUBLIC GTEST_USE_OWN_TR1_TUPLE=1)
|
||||
endif ()
|
||||
|
||||
set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
|
||||
add_library(test-main STATIC ${TEST_MAIN_SRC})
|
||||
target_link_libraries(test-main cppformat gmock)
|
||||
@ -14,14 +59,6 @@ function(add_fmt_test name)
|
||||
add_test(NAME ${name} COMMAND ${name})
|
||||
endfunction()
|
||||
|
||||
check_cxx_source_compiles("
|
||||
enum C : char {A};
|
||||
int main() {}"
|
||||
HAVE_ENUM_BASE)
|
||||
if (HAVE_ENUM_BASE)
|
||||
add_definitions(-DFMT_USE_ENUM_BASE=1)
|
||||
endif ()
|
||||
|
||||
add_fmt_test(assert-test)
|
||||
add_fmt_test(gtest-extra-test)
|
||||
add_fmt_test(format-test)
|
||||
@ -45,6 +82,15 @@ if (CPP11_FLAG)
|
||||
set_target_properties(util-test PROPERTIES COMPILE_FLAGS ${CPP11_FLAG})
|
||||
endif ()
|
||||
|
||||
check_cxx_source_compiles("
|
||||
enum C : char {A};
|
||||
int main() {}"
|
||||
HAVE_ENUM_BASE)
|
||||
if (HAVE_ENUM_BASE)
|
||||
set_target_properties(util-test
|
||||
PROPERTIES COMPILE_DEFINITIONS "FMT_USE_ENUM_BASE=1")
|
||||
endif ()
|
||||
|
||||
foreach (src ${FMT_SOURCES})
|
||||
set(FMT_TEST_SOURCES ${FMT_TEST_SOURCES} ../${src})
|
||||
endforeach ()
|
||||
@ -55,7 +101,10 @@ check_cxx_source_compiles("
|
||||
int main() { static_assert(!std::is_copy_assignable<C>::value, \"\"); }"
|
||||
HAVE_TYPE_TRAITS)
|
||||
if (HAVE_TYPE_TRAITS)
|
||||
add_definitions(-DFMT_USE_TYPE_TRAITS=1)
|
||||
foreach (target format-test util-test)
|
||||
set_target_properties(${target}
|
||||
PROPERTIES COMPILE_DEFINITIONS "FMT_USE_TYPE_TRAITS=1")
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
add_executable(macro-test macro-test.cc ${FMT_TEST_SOURCES} ${TEST_MAIN_SRC})
|
||||
@ -82,6 +131,15 @@ if (HAVE_FNO_EXCEPTIONS_FLAG)
|
||||
PROPERTIES COMPILE_FLAGS -fno-exceptions)
|
||||
endif ()
|
||||
|
||||
# Test compilation with default flags.
|
||||
if (FMT_TEST_DEFAULT_FLAGS)
|
||||
file(GLOB src RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cc *.h)
|
||||
foreach (s ${FMT_SOURCES})
|
||||
set(src ${src} ../${s})
|
||||
endforeach ()
|
||||
add_library(testformat STATIC ${src})
|
||||
endif ()
|
||||
|
||||
if (FMT_PEDANTIC)
|
||||
add_test(compile-test ${CMAKE_CTEST_COMMAND}
|
||||
--build-and-test
|
||||
|
@ -148,19 +148,6 @@ TEST(CStringRefTest, Ctor) {
|
||||
EXPECT_STREQ("defg", CStringRef(std::string("defg")).c_str());
|
||||
}
|
||||
|
||||
class TestString {
|
||||
private:
|
||||
std::string value_;
|
||||
|
||||
public:
|
||||
explicit TestString(const char *value = "") : value_(value) {}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const TestString &s) {
|
||||
os << s.value_;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
#if FMT_USE_TYPE_TRAITS
|
||||
TEST(WriterTest, NotCopyConstructible) {
|
||||
EXPECT_FALSE(std::is_copy_constructible<BasicWriter<char> >::value);
|
||||
@ -1615,3 +1602,33 @@ TEST(FormatTest, MaxArgs) {
|
||||
fmt::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e'));
|
||||
}
|
||||
|
||||
#if FMT_USE_USER_DEFINED_LITERALS
|
||||
// Passing user-defined literals directly to EXPECT_EQ causes problems
|
||||
// with macro argument stringification (#) on some versions of GCC.
|
||||
// Workaround: Assing the UDL result to a variable before the macro.
|
||||
|
||||
using namespace fmt::literals;
|
||||
|
||||
TEST(LiteralsTest, Format) {
|
||||
auto udl_format = "{}c{}"_format("ab", 1);
|
||||
EXPECT_EQ(format("{}c{}", "ab", 1), udl_format);
|
||||
auto udl_format_w = L"{}c{}"_format(L"ab", 1);
|
||||
EXPECT_EQ(format(L"{}c{}", L"ab", 1), udl_format_w);
|
||||
}
|
||||
|
||||
TEST(LiteralsTest, NamedArg) {
|
||||
auto udl_a = format("{first}{second}{first}{third}",
|
||||
"first"_a="abra", "second"_a="cad", "third"_a=99);
|
||||
EXPECT_EQ(format("{first}{second}{first}{third}",
|
||||
fmt::arg("first", "abra"), fmt::arg("second", "cad"),
|
||||
fmt::arg("third", 99)),
|
||||
udl_a);
|
||||
auto udl_a_w = format(L"{first}{second}{first}{third}",
|
||||
L"first"_a=L"abra", L"second"_a=L"cad", L"third"_a=99);
|
||||
EXPECT_EQ(format(L"{first}{second}{first}{third}",
|
||||
fmt::arg(L"first", L"abra"), fmt::arg(L"second", L"cad"),
|
||||
fmt::arg(L"third", 99)),
|
||||
udl_a_w);
|
||||
}
|
||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||
|
@ -100,7 +100,7 @@ struct S {};
|
||||
|
||||
int test_variadic(FMT_GEN(10, GET_TYPE), const fmt::ArgList &args) { \
|
||||
int result = 0; \
|
||||
for (std::size_t i = 0; args[i].type; ++i) \
|
||||
for (unsigned i = 0; args[i].type; ++i) \
|
||||
result += args[i].int_value; \
|
||||
return result;
|
||||
}
|
||||
|
@ -426,6 +426,10 @@ TEST(PrintfTest, Pointer) {
|
||||
EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
|
||||
}
|
||||
|
||||
TEST(PrintfTest, Custom) {
|
||||
EXPECT_PRINTF("abc", "%s", TestString("abc"));
|
||||
}
|
||||
|
||||
TEST(PrintfTest, Location) {
|
||||
// TODO: test %n
|
||||
}
|
||||
@ -452,3 +456,7 @@ TEST(PrintfTest, PrintfError) {
|
||||
EXPECT_LT(result, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(PrintfTest, WideString) {
|
||||
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", TestWString(L"abc")));
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -52,5 +53,10 @@ int main(int argc, char **argv) {
|
||||
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
||||
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
try {
|
||||
return RUN_ALL_TESTS();
|
||||
} catch (...) {
|
||||
// Catch all exceptions to make Coverity happy.
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -726,12 +726,14 @@ TEST(UtilTest, UTF8ToUTF16) {
|
||||
}
|
||||
|
||||
template <typename Converter, typename Char>
|
||||
void check_utf_conversion_error(const char *message) {
|
||||
void check_utf_conversion_error(
|
||||
const char *message,
|
||||
fmt::BasicStringRef<Char> str = fmt::BasicStringRef<Char>(0, 0)) {
|
||||
fmt::MemoryWriter out;
|
||||
fmt::internal::format_windows_error(out, ERROR_INVALID_PARAMETER, message);
|
||||
fmt::SystemError error(0, "");
|
||||
try {
|
||||
Converter(fmt::BasicStringRef<Char>(0, 0));
|
||||
(Converter)(str);
|
||||
} catch (const fmt::SystemError &e) {
|
||||
error = e;
|
||||
}
|
||||
@ -745,13 +747,17 @@ TEST(UtilTest, UTF16ToUTF8Error) {
|
||||
}
|
||||
|
||||
TEST(UtilTest, UTF8ToUTF16Error) {
|
||||
const char *message = "cannot convert string from UTF-8 to UTF-16";
|
||||
check_utf_conversion_error<fmt::internal::UTF8ToUTF16, char>(message);
|
||||
check_utf_conversion_error<fmt::internal::UTF8ToUTF16, char>(
|
||||
"cannot convert string from UTF-8 to UTF-16");
|
||||
message, fmt::StringRef("foo", INT_MAX + 1u));
|
||||
}
|
||||
|
||||
TEST(UtilTest, UTF16ToUTF8Convert) {
|
||||
fmt::internal::UTF16ToUTF8 u;
|
||||
EXPECT_EQ(ERROR_INVALID_PARAMETER, u.convert(fmt::WStringRef(0, 0)));
|
||||
EXPECT_EQ(ERROR_INVALID_PARAMETER,
|
||||
u.convert(fmt::WStringRef(L"foo", INT_MAX + 1u)));
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
|
23
test/util.h
23
test/util.h
@ -67,3 +67,26 @@ inline FILE *safe_fopen(const char *filename, const char *mode) {
|
||||
return std::fopen(filename, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
class BasicTestString {
|
||||
private:
|
||||
std::basic_string<Char> value_;
|
||||
|
||||
static const Char EMPTY[];
|
||||
|
||||
public:
|
||||
explicit BasicTestString(const Char *value = EMPTY) : value_(value) {}
|
||||
|
||||
friend std::basic_ostream<Char> &operator<<(
|
||||
std::basic_ostream<Char> &os, const BasicTestString &s) {
|
||||
os << s.value_;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
const Char BasicTestString<Char>::EMPTY[] = {0};
|
||||
|
||||
typedef BasicTestString<char> TestString;
|
||||
typedef BasicTestString<wchar_t> TestWString;
|
||||
|
Loading…
Reference in New Issue
Block a user