Update coverity branch

This commit is contained in:
vitaut 2015-10-19 07:59:45 -07:00
commit 566f393b49
20 changed files with 433 additions and 185 deletions

1
.gitignore vendored
View File

@ -14,3 +14,4 @@ CTestTestfile.cmake
CMakeCache.txt
CMakeFiles
Makefile
run-msbuild.bat

View File

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

View File

@ -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>`_

View File

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

View File

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

View File

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

View File

@ -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__':

View File

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

View File

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

View File

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

View File

@ -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
View File

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

View File

@ -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']

View File

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

View File

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

View File

@ -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;
}

View File

@ -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")));
}

View File

@ -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;
}

View File

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

View File

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