Update coverity branch
This commit is contained in:
commit
566f393b49
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,3 +14,4 @@ CTestTestfile.cmake
|
|||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
CMakeFiles
|
CMakeFiles
|
||||||
Makefile
|
Makefile
|
||||||
|
run-msbuild.bat
|
||||||
|
100
CMakeLists.txt
100
CMakeLists.txt
@ -12,6 +12,11 @@ endif ()
|
|||||||
|
|
||||||
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
|
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)
|
project(FORMAT)
|
||||||
|
|
||||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
@ -90,7 +95,7 @@ if (BIICODE)
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_library(cppformat ${FMT_SOURCES})
|
add_library(cppformat ${FMT_SOURCES})
|
||||||
if (BUILD_SHARED_LIBS)
|
if (BUILD_SHARED_LIBS AND UNIX AND NOT APPLE)
|
||||||
# Fix rpmlint warning:
|
# Fix rpmlint warning:
|
||||||
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
|
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
|
||||||
target_link_libraries(cppformat -Wl,--as-needed)
|
target_link_libraries(cppformat -Wl,--as-needed)
|
||||||
@ -106,89 +111,21 @@ endif ()
|
|||||||
# over compile options, so the options used here only matter for testing.
|
# over compile options, so the options used here only matter for testing.
|
||||||
if (CPP11_FLAG AND FMT_PEDANTIC)
|
if (CPP11_FLAG AND FMT_PEDANTIC)
|
||||||
set(FMT_EXTRA_COMPILE_FLAGS "${FMT_EXTRA_COMPILE_FLAGS} ${CPP11_FLAG}")
|
set(FMT_EXTRA_COMPILE_FLAGS "${FMT_EXTRA_COMPILE_FLAGS} ${CPP11_FLAG}")
|
||||||
# Test compilation with default flags.
|
set(FMT_TEST_DEFAULT_FLAGS TRUE)
|
||||||
file(GLOB src RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test/*.cc test/*.h)
|
|
||||||
add_library(testformat STATIC ${FMT_SOURCE_FILES} ${src})
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set_target_properties(cppformat
|
set_target_properties(cppformat
|
||||||
PROPERTIES COMPILE_FLAGS "${FMT_EXTRA_COMPILE_FLAGS}")
|
PROPERTIES COMPILE_FLAGS "${FMT_EXTRA_COMPILE_FLAGS}")
|
||||||
|
|
||||||
add_subdirectory(doc)
|
if (FMT_DOC)
|
||||||
|
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)
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Check if variadic templates are working and not affected by GCC bug 39653:
|
if (FMT_TEST)
|
||||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
|
enable_testing()
|
||||||
check_cxx_source_compiles("
|
add_subdirectory(test)
|
||||||
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 ()
|
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_MAJOR 1)
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR 2)
|
set(CPACK_PACKAGE_VERSION_MINOR 2)
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||||
@ -206,7 +143,8 @@ if (EXISTS .gitignore)
|
|||||||
string(REPLACE "*" ".*" line "${line}")
|
string(REPLACE "*" ".*" line "${line}")
|
||||||
set(ignored_files ${ignored_files} "${line}$" "${line}/")
|
set(ignored_files ${ignored_files} "${line}$" "${line}/")
|
||||||
endforeach ()
|
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_GENERATOR ZIP)
|
||||||
set(CPACK_SOURCE_IGNORE_FILES ${ignored_files})
|
set(CPACK_SOURCE_IGNORE_FILES ${ignored_files})
|
||||||
@ -216,7 +154,9 @@ if (EXISTS .gitignore)
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Install targets.
|
# Install targets.
|
||||||
set(FMT_LIB_DIR lib CACHE STRING
|
if (FMT_INSTALL)
|
||||||
"Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.")
|
set(FMT_LIB_DIR lib CACHE STRING
|
||||||
install(TARGETS cppformat DESTINATION ${FMT_LIB_DIR})
|
"Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.")
|
||||||
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
|
* `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/>`_:
|
* `Saddy <https://code.google.com/p/saddy/>`_:
|
||||||
Small crossplatform 2D graphic engine
|
Small crossplatform 2D graphic engine
|
||||||
|
|
||||||
@ -157,6 +159,10 @@ Projects using this library
|
|||||||
|
|
||||||
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging 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
|
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source MMORPG framework
|
||||||
|
|
||||||
`More... <https://github.com/search?q=cppformat&type=Code>`_
|
`More... <https://github.com/search?q=cppformat&type=Code>`_
|
||||||
|
10
appveyor.yml
10
appveyor.yml
@ -1,14 +1,14 @@
|
|||||||
|
configuration:
|
||||||
|
- Debug
|
||||||
|
- Release
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
CTEST_OUTPUT_ON_FAILURE: 1
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
matrix:
|
matrix:
|
||||||
- BUILD: msvc
|
- BUILD: msvc
|
||||||
CONFIG: Debug
|
|
||||||
- BUILD: msvc
|
- BUILD: msvc
|
||||||
CONFIG: Release
|
PLATFORM: x64
|
||||||
- BUILD: mingw
|
- BUILD: mingw
|
||||||
CONFIG: Debug
|
|
||||||
- BUILD: mingw
|
|
||||||
CONFIG: Release
|
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- python support/appveyor-build.py
|
- python support/appveyor-build.py
|
||||||
|
@ -6,4 +6,5 @@ endif ()
|
|||||||
|
|
||||||
add_custom_target(doc COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py)
|
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:: format(CStringRef, ArgList)
|
||||||
|
|
||||||
|
.. doxygenfunction:: operator""_format(const char *, std::size_t)
|
||||||
|
|
||||||
.. _print:
|
.. _print:
|
||||||
|
|
||||||
.. doxygenfunction:: print(CStringRef, ArgList)
|
.. doxygenfunction:: print(CStringRef, ArgList)
|
||||||
@ -74,6 +76,8 @@ Utilities
|
|||||||
|
|
||||||
.. doxygenfunction:: fmt::arg(StringRef, const T&)
|
.. doxygenfunction:: fmt::arg(StringRef, const T&)
|
||||||
|
|
||||||
|
.. doxygenfunction:: operator""_a(const char *, std::size_t)
|
||||||
|
|
||||||
.. doxygendefine:: FMT_CAPTURE
|
.. doxygendefine:: FMT_CAPTURE
|
||||||
|
|
||||||
.. doxygendefine:: FMT_VARIADIC
|
.. doxygendefine:: FMT_VARIADIC
|
||||||
|
71
doc/build.py
71
doc/build.py
@ -1,26 +1,22 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python
|
||||||
# Build the documentation.
|
# Build the documentation.
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import os, shutil, tempfile
|
import errno, os, shutil, sys, tempfile
|
||||||
from subprocess import check_call, CalledProcessError, Popen, PIPE
|
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."
|
"Install package using pip."
|
||||||
if commit:
|
if commit:
|
||||||
cmd = ['pip', 'show', package.split('/')[1]]
|
check_version = kwargs.get('check_version', '')
|
||||||
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
#output = check_output(['pip', 'show', package.split('/')[1]])
|
||||||
stdout, stderr = p.communicate()
|
#if check_version in output:
|
||||||
if stdout:
|
# print('{} already installed'.format(package))
|
||||||
return # Already installed
|
# return
|
||||||
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)
|
|
||||||
package = 'git+git://github.com/{0}.git@{1}'.format(package, commit)
|
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():
|
def build_docs():
|
||||||
# Create virtualenv.
|
# Create virtualenv.
|
||||||
@ -28,9 +24,28 @@ def build_docs():
|
|||||||
virtualenv_dir = 'virtualenv'
|
virtualenv_dir = 'virtualenv'
|
||||||
check_call(['virtualenv', virtualenv_dir])
|
check_call(['virtualenv', virtualenv_dir])
|
||||||
activate_this_file = os.path.join(virtualenv_dir, 'bin', 'activate_this.py')
|
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.
|
# 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',
|
pip_install('michaeljones/breathe',
|
||||||
'511b0887293e7c6b12310bb61b3659068f48f0f4')
|
'511b0887293e7c6b12310bb61b3659068f48f0f4')
|
||||||
# Build docs.
|
# Build docs.
|
||||||
@ -43,7 +58,6 @@ def build_docs():
|
|||||||
GENERATE_RTF = NO
|
GENERATE_RTF = NO
|
||||||
CASE_SENSE_NAMES = NO
|
CASE_SENSE_NAMES = NO
|
||||||
INPUT = {0}/format.h
|
INPUT = {0}/format.h
|
||||||
EXCLUDE_SYMBOLS = fmt::internal::*
|
|
||||||
QUIET = YES
|
QUIET = YES
|
||||||
JAVADOC_AUTOBRIEF = YES
|
JAVADOC_AUTOBRIEF = YES
|
||||||
AUTOLINK_SUPPORT = NO
|
AUTOLINK_SUPPORT = NO
|
||||||
@ -54,18 +68,25 @@ def build_docs():
|
|||||||
ALIASES += "endrst=\endverbatim"
|
ALIASES += "endrst=\endverbatim"
|
||||||
PREDEFINED = _WIN32=1 \
|
PREDEFINED = _WIN32=1 \
|
||||||
FMT_USE_VARIADIC_TEMPLATES=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
|
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:
|
if p.returncode != 0:
|
||||||
raise CalledProcessError(p.returncode, cmd)
|
raise CalledProcessError(p.returncode, cmd)
|
||||||
check_call(['sphinx-build', '-D',
|
check_call(['sphinx-build', '-D',
|
||||||
'breathe_projects.format=' + os.path.join(os.getcwd(), 'doxyxml'),
|
'breathe_projects.format=' + os.path.join(os.getcwd(), 'doxyxml'),
|
||||||
'-b', 'html', doc_dir, 'html'])
|
'-b', 'html', doc_dir, 'html'])
|
||||||
check_call(['lessc', '--clean-css',
|
try:
|
||||||
'--include-path=' + os.path.join(doc_dir, 'bootstrap'),
|
check_call(['lessc', '--clean-css',
|
||||||
os.path.join(doc_dir, 'cppformat.less'),
|
'--include-path=' + os.path.join(doc_dir, 'bootstrap'),
|
||||||
'html/_static/cppformat.css'])
|
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'
|
return 'html'
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -13,11 +13,6 @@ html {
|
|||||||
background-color: darken(@header-bg, 10%);
|
background-color: darken(@header-bg, 10%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-content {
|
|
||||||
.make-md-column-offset(2);
|
|
||||||
.make-md-column(8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.jumbotron {
|
.jumbotron {
|
||||||
#gradient > .vertical(@header-bg; darken(@header-bg, 2%); 50%; 50%);
|
#gradient > .vertical(@header-bg; darken(@header-bg, 2%); 50%; 50%);
|
||||||
background-size: 100% 4px;
|
background-size: 100% 4px;
|
||||||
@ -32,9 +27,11 @@ div.sphinxsidebar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Keep content not too wide for better readability.
|
// Keep content not too wide for better readability.
|
||||||
.content {
|
.navbar-content, .content {
|
||||||
.make-md-column-offset(2);
|
.make-md-column-offset(1);
|
||||||
.make-md-column(8);
|
.make-md-column(10);
|
||||||
|
.make-lg-column-offset(2);
|
||||||
|
.make-lg-column(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.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");
|
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:
|
||||||
|
|
||||||
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
|
* Mac OS X with GCC 4.2.1 and Clang 4.2, 5.1.0
|
||||||
|
|
||||||
* 64-bit Windows with Visual C++ 2010 and
|
* 64-bit Windows with Visual C++ 2010, 2013 and
|
||||||
`2013 <https://ci.appveyor.com/project/vitaut/cppformat>`_
|
`2015 <https://ci.appveyor.com/project/vitaut/cppformat>`_
|
||||||
|
|
||||||
* 32-bit Windows with Visual C++ 2010
|
* 32-bit Windows with Visual C++ 2010
|
||||||
|
|
||||||
Although the library uses C++11 features when available, it also works with older
|
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,
|
The output of all formatting functions is consistent across platforms. In particular,
|
||||||
formatting a floating-point infinity always gives ``inf`` while the output
|
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
|
__ 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
|
Android NDK
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
23
format.cc
23
format.cc
@ -523,6 +523,13 @@ class PrintfArgFormatter :
|
|||||||
}
|
}
|
||||||
*out = static_cast<Char>(value);
|
*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 internal
|
||||||
} // namespace fmt
|
} // namespace fmt
|
||||||
@ -612,14 +619,17 @@ FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
|
|||||||
#if FMT_USE_WINDOWS_H
|
#if FMT_USE_WINDOWS_H
|
||||||
|
|
||||||
FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
|
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";
|
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)
|
if (length == 0)
|
||||||
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
|
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
|
||||||
buffer_.resize(length + 1);
|
buffer_.resize(length + 1);
|
||||||
length = MultiByteToWideChar(
|
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)
|
if (length == 0)
|
||||||
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
|
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
|
||||||
buffer_[length] = 0;
|
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) {
|
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)
|
if (length == 0)
|
||||||
return GetLastError();
|
return GetLastError();
|
||||||
buffer_.resize(length + 1);
|
buffer_.resize(length + 1);
|
||||||
length = WideCharToMultiByte(
|
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)
|
if (length == 0)
|
||||||
return GetLastError();
|
return GetLastError();
|
||||||
buffer_[length] = 0;
|
buffer_[length] = 0;
|
||||||
|
148
format.h
148
format.h
@ -38,9 +38,16 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#ifndef FMT_USE_IOSTREAMS
|
||||||
|
# define FMT_USE_IOSTREAMS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FMT_USE_IOSTREAMS
|
||||||
|
# include <sstream>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if _SECURE_SCL
|
#if _SECURE_SCL
|
||||||
# include <iterator>
|
# include <iterator>
|
||||||
#endif
|
#endif
|
||||||
@ -177,6 +184,16 @@ inline uint32_t clzll(uint64_t x) {
|
|||||||
TypeName& operator=(const TypeName&)
|
TypeName& operator=(const TypeName&)
|
||||||
#endif
|
#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
|
#ifndef FMT_ASSERT
|
||||||
# define FMT_ASSERT(condition, message) assert((condition) && message)
|
# define FMT_ASSERT(condition, message) assert((condition) && message)
|
||||||
#endif
|
#endif
|
||||||
@ -285,7 +302,6 @@ class BasicStringRef {
|
|||||||
typedef BasicStringRef<char> StringRef;
|
typedef BasicStringRef<char> StringRef;
|
||||||
typedef BasicStringRef<wchar_t> WStringRef;
|
typedef BasicStringRef<wchar_t> WStringRef;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
A reference to a null terminated string. It can be constructed from a C
|
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:
|
private:
|
||||||
T data_[SIZE];
|
T data_[SIZE];
|
||||||
|
|
||||||
// Free memory allocated by the buffer.
|
// Deallocate memory allocated by the buffer.
|
||||||
void free() {
|
void deallocate() {
|
||||||
if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_);
|
if (this->ptr_ != data_) Allocator::deallocate(this->ptr_, this->capacity_);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -460,7 +476,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
|
|||||||
public:
|
public:
|
||||||
explicit MemoryBuffer(const Allocator &alloc = Allocator())
|
explicit MemoryBuffer(const Allocator &alloc = Allocator())
|
||||||
: Allocator(alloc), Buffer<T>(data_, SIZE) {}
|
: Allocator(alloc), Buffer<T>(data_, SIZE) {}
|
||||||
~MemoryBuffer() { free(); }
|
~MemoryBuffer() { deallocate(); }
|
||||||
|
|
||||||
#if FMT_USE_RVALUE_REFERENCES
|
#if FMT_USE_RVALUE_REFERENCES
|
||||||
private:
|
private:
|
||||||
@ -477,7 +493,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
|
|||||||
} else {
|
} else {
|
||||||
this->ptr_ = other.ptr_;
|
this->ptr_ = other.ptr_;
|
||||||
// Set pointer to the inline array so that delete is not called
|
// Set pointer to the inline array so that delete is not called
|
||||||
// when freeing.
|
// when deallocating.
|
||||||
other.ptr_ = other.data_;
|
other.ptr_ = other.data_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -489,7 +505,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
|
|||||||
|
|
||||||
MemoryBuffer &operator=(MemoryBuffer &&other) {
|
MemoryBuffer &operator=(MemoryBuffer &&other) {
|
||||||
assert(this != &other);
|
assert(this != &other);
|
||||||
free();
|
deallocate();
|
||||||
move(other);
|
move(other);
|
||||||
return *this;
|
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
|
// the buffer already uses the new storage and will deallocate it in case
|
||||||
// of exception.
|
// of exception.
|
||||||
if (old_ptr != data_)
|
if (old_ptr != data_)
|
||||||
this->deallocate(old_ptr, old_capacity);
|
Allocator::deallocate(old_ptr, old_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A fixed-size buffer.
|
// A fixed-size buffer.
|
||||||
@ -712,24 +728,23 @@ inline unsigned count_digits(uint32_t n) {
|
|||||||
// Formats a decimal unsigned integer value writing into buffer.
|
// Formats a decimal unsigned integer value writing into buffer.
|
||||||
template <typename UInt, typename Char>
|
template <typename UInt, typename Char>
|
||||||
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
|
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
|
||||||
--num_digits;
|
buffer += num_digits;
|
||||||
while (value >= 100) {
|
while (value >= 100) {
|
||||||
// Integer division is slow so do it for a group of two digits instead
|
// 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
|
// of for every digit. The idea comes from the talk by Alexandrescu
|
||||||
// "Three Optimization Tips for C++". See speed-test for a comparison.
|
// "Three Optimization Tips for C++". See speed-test for a comparison.
|
||||||
unsigned index = (value % 100) * 2;
|
unsigned index = (value % 100) * 2;
|
||||||
value /= 100;
|
value /= 100;
|
||||||
buffer[num_digits] = Data::DIGITS[index + 1];
|
*--buffer = Data::DIGITS[index + 1];
|
||||||
buffer[num_digits - 1] = Data::DIGITS[index];
|
*--buffer = Data::DIGITS[index];
|
||||||
num_digits -= 2;
|
|
||||||
}
|
}
|
||||||
if (value < 10) {
|
if (value < 10) {
|
||||||
*buffer = static_cast<char>('0' + value);
|
*--buffer = static_cast<char>('0' + value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unsigned index = static_cast<unsigned>(value * 2);
|
unsigned index = static_cast<unsigned>(value * 2);
|
||||||
buffer[1] = Data::DIGITS[index + 1];
|
*--buffer = Data::DIGITS[index + 1];
|
||||||
buffer[0] = Data::DIGITS[index];
|
*--buffer = Data::DIGITS[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@ -1047,7 +1062,7 @@ struct NamedArg : Arg {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
NamedArg(BasicStringRef<Char> argname, const T &value)
|
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));
|
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);
|
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>
|
template <typename Char>
|
||||||
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) {
|
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) {
|
||||||
internal::PrintfFormatter<Char>(args).format(w, format);
|
internal::PrintfFormatter<Char>(args).format(w, format);
|
||||||
@ -2708,6 +2712,12 @@ inline std::string sprintf(CStringRef format, ArgList args) {
|
|||||||
return w.str();
|
return w.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::wstring sprintf(WCStringRef format, ArgList args) {
|
||||||
|
WMemoryWriter w;
|
||||||
|
printf(w, format, args);
|
||||||
|
return w.str();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Prints formatted data to the file *f*.
|
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_W(std::wstring, format, WCStringRef)
|
||||||
FMT_VARIADIC(void, print, CStringRef)
|
FMT_VARIADIC(void, print, CStringRef)
|
||||||
FMT_VARIADIC(void, print, std::FILE *, CStringRef)
|
FMT_VARIADIC(void, print, std::FILE *, CStringRef)
|
||||||
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
|
|
||||||
FMT_VARIADIC(void, print_colored, Color, CStringRef)
|
FMT_VARIADIC(void, print_colored, Color, CStringRef)
|
||||||
FMT_VARIADIC(std::string, sprintf, CStringRef)
|
FMT_VARIADIC(std::string, sprintf, CStringRef)
|
||||||
|
FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
|
||||||
FMT_VARIADIC(int, printf, CStringRef)
|
FMT_VARIADIC(int, printf, CStringRef)
|
||||||
FMT_VARIADIC(int, fprintf, std::FILE *, 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.
|
// Restore warnings.
|
||||||
#if FMT_GCC_VERSION >= 406
|
#if FMT_GCC_VERSION >= 406
|
||||||
|
@ -5,7 +5,8 @@ import os
|
|||||||
from subprocess import check_call
|
from subprocess import check_call
|
||||||
|
|
||||||
build = os.environ['BUILD']
|
build = os.environ['BUILD']
|
||||||
config = os.environ['CONFIG']
|
config = os.environ['CONFIGURATION']
|
||||||
|
platform = os.environ.get('PLATFORM')
|
||||||
path = os.environ['PATH']
|
path = os.environ['PATH']
|
||||||
cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config]
|
cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config]
|
||||||
if build == 'mingw':
|
if build == 'mingw':
|
||||||
@ -19,6 +20,10 @@ else:
|
|||||||
# Add MSBuild 14.0 to PATH as described in
|
# Add MSBuild 14.0 to PATH as described in
|
||||||
# http://help.appveyor.com/discussions/problems/2229-v140-not-found-on-vs2105rc.
|
# 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
|
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']
|
build_command = ['msbuild', '/m:4', '/p:Config=' + config, 'FORMAT.sln']
|
||||||
test_command = ['msbuild', 'RUN_TESTS.vcxproj']
|
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)
|
set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
|
||||||
add_library(test-main STATIC ${TEST_MAIN_SRC})
|
add_library(test-main STATIC ${TEST_MAIN_SRC})
|
||||||
target_link_libraries(test-main cppformat gmock)
|
target_link_libraries(test-main cppformat gmock)
|
||||||
@ -14,14 +59,6 @@ function(add_fmt_test name)
|
|||||||
add_test(NAME ${name} COMMAND ${name})
|
add_test(NAME ${name} COMMAND ${name})
|
||||||
endfunction()
|
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(assert-test)
|
||||||
add_fmt_test(gtest-extra-test)
|
add_fmt_test(gtest-extra-test)
|
||||||
add_fmt_test(format-test)
|
add_fmt_test(format-test)
|
||||||
@ -45,6 +82,15 @@ if (CPP11_FLAG)
|
|||||||
set_target_properties(util-test PROPERTIES COMPILE_FLAGS ${CPP11_FLAG})
|
set_target_properties(util-test PROPERTIES COMPILE_FLAGS ${CPP11_FLAG})
|
||||||
endif ()
|
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})
|
foreach (src ${FMT_SOURCES})
|
||||||
set(FMT_TEST_SOURCES ${FMT_TEST_SOURCES} ../${src})
|
set(FMT_TEST_SOURCES ${FMT_TEST_SOURCES} ../${src})
|
||||||
endforeach ()
|
endforeach ()
|
||||||
@ -55,7 +101,10 @@ check_cxx_source_compiles("
|
|||||||
int main() { static_assert(!std::is_copy_assignable<C>::value, \"\"); }"
|
int main() { static_assert(!std::is_copy_assignable<C>::value, \"\"); }"
|
||||||
HAVE_TYPE_TRAITS)
|
HAVE_TYPE_TRAITS)
|
||||||
if (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 ()
|
endif ()
|
||||||
|
|
||||||
add_executable(macro-test macro-test.cc ${FMT_TEST_SOURCES} ${TEST_MAIN_SRC})
|
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)
|
PROPERTIES COMPILE_FLAGS -fno-exceptions)
|
||||||
endif ()
|
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)
|
if (FMT_PEDANTIC)
|
||||||
add_test(compile-test ${CMAKE_CTEST_COMMAND}
|
add_test(compile-test ${CMAKE_CTEST_COMMAND}
|
||||||
--build-and-test
|
--build-and-test
|
||||||
|
@ -148,19 +148,6 @@ TEST(CStringRefTest, Ctor) {
|
|||||||
EXPECT_STREQ("defg", CStringRef(std::string("defg")).c_str());
|
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
|
#if FMT_USE_TYPE_TRAITS
|
||||||
TEST(WriterTest, NotCopyConstructible) {
|
TEST(WriterTest, NotCopyConstructible) {
|
||||||
EXPECT_FALSE(std::is_copy_constructible<BasicWriter<char> >::value);
|
EXPECT_FALSE(std::is_copy_constructible<BasicWriter<char> >::value);
|
||||||
@ -1615,3 +1602,33 @@ TEST(FormatTest, MaxArgs) {
|
|||||||
fmt::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
|
fmt::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e'));
|
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 test_variadic(FMT_GEN(10, GET_TYPE), const fmt::ArgList &args) { \
|
||||||
int result = 0; \
|
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; \
|
result += args[i].int_value; \
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -426,6 +426,10 @@ TEST(PrintfTest, Pointer) {
|
|||||||
EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
|
EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(PrintfTest, Custom) {
|
||||||
|
EXPECT_PRINTF("abc", "%s", TestString("abc"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, Location) {
|
TEST(PrintfTest, Location) {
|
||||||
// TODO: test %n
|
// TODO: test %n
|
||||||
}
|
}
|
||||||
@ -452,3 +456,7 @@ TEST(PrintfTest, PrintfError) {
|
|||||||
EXPECT_LT(result, 0);
|
EXPECT_LT(result, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#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.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -52,5 +53,10 @@ int main(int argc, char **argv) {
|
|||||||
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
||||||
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
|
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
|
||||||
testing::InitGoogleTest(&argc, argv);
|
testing::InitGoogleTest(&argc, argv);
|
||||||
return RUN_ALL_TESTS();
|
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>
|
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::MemoryWriter out;
|
||||||
fmt::internal::format_windows_error(out, ERROR_INVALID_PARAMETER, message);
|
fmt::internal::format_windows_error(out, ERROR_INVALID_PARAMETER, message);
|
||||||
fmt::SystemError error(0, "");
|
fmt::SystemError error(0, "");
|
||||||
try {
|
try {
|
||||||
Converter(fmt::BasicStringRef<Char>(0, 0));
|
(Converter)(str);
|
||||||
} catch (const fmt::SystemError &e) {
|
} catch (const fmt::SystemError &e) {
|
||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
@ -745,13 +747,17 @@ TEST(UtilTest, UTF16ToUTF8Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(UtilTest, UTF8ToUTF16Error) {
|
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>(
|
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) {
|
TEST(UtilTest, UTF16ToUTF8Convert) {
|
||||||
fmt::internal::UTF16ToUTF8 u;
|
fmt::internal::UTF16ToUTF8 u;
|
||||||
EXPECT_EQ(ERROR_INVALID_PARAMETER, u.convert(fmt::WStringRef(0, 0)));
|
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
|
#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);
|
return std::fopen(filename, mode);
|
||||||
#endif
|
#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