mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-27 13:02:28 +00:00
Compare commits
26 Commits
nats
...
login-token-old
| Author | SHA1 | Date | |
|---|---|---|---|
| 9dd4002337 | |||
| ccdebf0116 | |||
| 1a4aa1692a | |||
| 6a79694fa1 | |||
| c52ff4249a | |||
| 0ba9b3fedc | |||
| 46561b9cf5 | |||
| 545ac6b420 | |||
| 0e8f6a32b1 | |||
| 17544d4577 | |||
| 563878f20e | |||
| ffbee0ad1a | |||
| 575ba28b62 | |||
| 3afee1f841 | |||
| 832c31a41a | |||
| ff13f162ce | |||
| 80f1c65e1c | |||
| 7d3f35d48b | |||
| 69c6879ac9 | |||
| bdc90ac3a7 | |||
| ab33148f81 | |||
| c2766db89d | |||
| 5f1063acb9 | |||
| 596e3b28b5 | |||
| 077ba02004 | |||
| 75ee3b30e2 |
+3
-1
@@ -309,7 +309,7 @@ IF(EQEMU_BUILD_PERL)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${PERL_INCLUDE_PATH}")
|
||||
ENDIF(EQEMU_BUILD_PERL)
|
||||
|
||||
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt)
|
||||
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt recast_navigation)
|
||||
|
||||
FIND_PACKAGE(Sodium REQUIRED)
|
||||
IF(SODIUM_FOUND)
|
||||
@@ -357,6 +357,8 @@ INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/cereal")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/include" )
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/src")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/format")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/recast/detour/include")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/recast/recast/include")
|
||||
|
||||
IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS OR EQEMU_BUILD_HC)
|
||||
ADD_SUBDIRECTORY(common)
|
||||
|
||||
@@ -3,6 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
SET(common_sources
|
||||
base_packet.cpp
|
||||
classes.cpp
|
||||
compression.cpp
|
||||
condition.cpp
|
||||
crash.cpp
|
||||
crc16.cpp
|
||||
@@ -113,6 +114,7 @@ SET(common_headers
|
||||
base_data.h
|
||||
bodytypes.h
|
||||
classes.h
|
||||
compression.h
|
||||
condition.h
|
||||
crash.h
|
||||
crc16.h
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "global_define.h"
|
||||
#include "types.h"
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
namespace EQEmu
|
||||
{
|
||||
uint32 EstimateDeflateBuffer(uint32 len) {
|
||||
z_stream zstream;
|
||||
memset(&zstream, 0, sizeof(zstream));
|
||||
|
||||
zstream.zalloc = Z_NULL;
|
||||
zstream.zfree = Z_NULL;
|
||||
zstream.opaque = Z_NULL;
|
||||
if (deflateInit(&zstream, Z_FINISH) != Z_OK)
|
||||
return 0;
|
||||
|
||||
return deflateBound(&zstream, len);
|
||||
}
|
||||
|
||||
uint32 DeflateData(const char *buffer, uint32 len, char *out_buffer, uint32 out_len_max) {
|
||||
z_stream zstream;
|
||||
memset(&zstream, 0, sizeof(zstream));
|
||||
int zerror;
|
||||
|
||||
zstream.next_in = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(buffer));
|
||||
zstream.avail_in = len;
|
||||
zstream.zalloc = Z_NULL;
|
||||
zstream.zfree = Z_NULL;
|
||||
zstream.opaque = Z_NULL;
|
||||
deflateInit(&zstream, Z_FINISH);
|
||||
|
||||
zstream.next_out = reinterpret_cast<unsigned char*>(out_buffer);
|
||||
zstream.avail_out = out_len_max;
|
||||
zerror = deflate(&zstream, Z_FINISH);
|
||||
|
||||
if (zerror == Z_STREAM_END)
|
||||
{
|
||||
deflateEnd(&zstream);
|
||||
return (uint32)zstream.total_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
zerror = deflateEnd(&zstream);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 InflateData(const char* buffer, uint32 len, char* out_buffer, uint32 out_len_max) {
|
||||
z_stream zstream;
|
||||
int zerror = 0;
|
||||
int i;
|
||||
|
||||
zstream.next_in = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(buffer));
|
||||
zstream.avail_in = len;
|
||||
zstream.next_out = reinterpret_cast<unsigned char*>(out_buffer);;
|
||||
zstream.avail_out = out_len_max;
|
||||
zstream.zalloc = Z_NULL;
|
||||
zstream.zfree = Z_NULL;
|
||||
zstream.opaque = Z_NULL;
|
||||
|
||||
i = inflateInit2(&zstream, 15);
|
||||
if (i != Z_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
zerror = inflate(&zstream, Z_FINISH);
|
||||
if (zerror == Z_STREAM_END) {
|
||||
inflateEnd(&zstream);
|
||||
return zstream.total_out;
|
||||
}
|
||||
else {
|
||||
if (zerror == -4 && zstream.msg == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
zerror = inflateEnd(&zstream);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace EQEmu
|
||||
{
|
||||
uint32 EstimateDeflateBuffer(uint32 len);
|
||||
uint32 DeflateData(const char *buffer, uint32 len, char *out_buffer, uint32 out_len_max);
|
||||
uint32 InflateData(const char* buffer, uint32 len, char* out_buffer, uint32 out_len_max);
|
||||
}
|
||||
@@ -1,32 +1,35 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include "../any.h"
|
||||
#include "event_loop.h"
|
||||
|
||||
namespace EQ {
|
||||
class BackgroundTask
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(void)> BackgroundTaskFunction;
|
||||
typedef std::function<void(EQEmu::Any&)> BackgroundTaskFunction;
|
||||
struct BackgroundTaskBaton
|
||||
{
|
||||
BackgroundTaskFunction fn;
|
||||
BackgroundTaskFunction on_finish;
|
||||
EQEmu::Any data;
|
||||
};
|
||||
|
||||
BackgroundTask(BackgroundTaskFunction fn, BackgroundTaskFunction on_finish) {
|
||||
BackgroundTask(BackgroundTaskFunction fn, BackgroundTaskFunction on_finish, EQEmu::Any data) {
|
||||
uv_work_t *m_work = new uv_work_t;
|
||||
memset(m_work, 0, sizeof(uv_work_t));
|
||||
BackgroundTaskBaton *baton = new BackgroundTaskBaton();
|
||||
baton->fn = fn;
|
||||
baton->on_finish = on_finish;
|
||||
baton->data = data;
|
||||
|
||||
m_work->data = baton;
|
||||
uv_queue_work(EventLoop::Get().Handle(), m_work, [](uv_work_t* req) {
|
||||
BackgroundTaskBaton *baton = (BackgroundTaskBaton*)req->data;
|
||||
baton->fn();
|
||||
baton->fn(baton->data);
|
||||
}, [](uv_work_t* req, int status) {
|
||||
BackgroundTaskBaton *baton = (BackgroundTaskBaton*)req->data;
|
||||
baton->on_finish();
|
||||
baton->on_finish(baton->data);
|
||||
delete baton;
|
||||
delete req;
|
||||
});
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
typedef const char Const_char;
|
||||
|
||||
#ifdef EMBPERL
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/useperl.h"
|
||||
#include "global_define.h"
|
||||
#include "eqdb.h"
|
||||
#include "useperl.h"
|
||||
|
||||
#ifdef THIS /* this macro seems to leak out on some systems */
|
||||
#undef THIS
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
typedef const char Const_char;
|
||||
|
||||
#ifdef EMBPERL
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/useperl.h"
|
||||
#include "global_define.h"
|
||||
#include "eqdb_res.h"
|
||||
#include "useperl.h"
|
||||
|
||||
|
||||
XS(XS_EQDBRes_num_rows); /* prototype to pass -Wmissing-prototypes */
|
||||
|
||||
@@ -151,6 +151,7 @@ RULE_BOOL(Character, UseOldBindWound, false) // Uses the original bind wound beh
|
||||
RULE_BOOL(Character, GrantHoTTOnCreate, false) // Grant Health of Target's Target leadership AA on character creation
|
||||
RULE_BOOL(Character, UseOldConSystem, false) // Grant Health of Target's Target leadership AA on character creation
|
||||
RULE_BOOL(Character, OPClientUpdateVisualDebug, false) // Shows a pulse and forward directional particle each time the client sends its position to server
|
||||
RULE_BOOL(Character, AllowCrossClassTrainers, false)
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
|
||||
+2
-1
@@ -3,4 +3,5 @@ IF(EQEMU_BUILD_LUA)
|
||||
ENDIF(EQEMU_BUILD_LUA)
|
||||
|
||||
ADD_SUBDIRECTORY(libuv)
|
||||
ADD_SUBDIRECTORY(format)
|
||||
ADD_SUBDIRECTORY(format)
|
||||
ADD_SUBDIRECTORY(recast)
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
<!---
|
||||
Please make sure you've followed the guidelines outlined in the CONTRIBUTING.rst file.
|
||||
--->
|
||||
@@ -0,0 +1,19 @@
|
||||
bin/
|
||||
/_CPack_Packages
|
||||
/doc/doxyxml
|
||||
/doc/html
|
||||
virtualenv
|
||||
/Testing
|
||||
/install_manifest.txt
|
||||
*~
|
||||
*.a
|
||||
*.so*
|
||||
*.zip
|
||||
cmake_install.cmake
|
||||
CPack*.cmake
|
||||
fmt-*.cmake
|
||||
CTestTestfile.cmake
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
Makefile
|
||||
run-msbuild.bat
|
||||
@@ -1,4 +1,5 @@
|
||||
language: cpp
|
||||
dist: trusty
|
||||
sudo: required # the doc target uses sudo to install dependencies
|
||||
|
||||
os:
|
||||
@@ -22,12 +23,5 @@ matrix:
|
||||
- os: osx
|
||||
env: BUILD=Doc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- kubuntu-backports # cmake 2.8.12
|
||||
packages:
|
||||
- cmake
|
||||
|
||||
script:
|
||||
- support/travis-build.py
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
message(STATUS "CMake version: ${CMAKE_VERSION}")
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
# Determine if fmt is built as a subproject (using add_subdirectory)
|
||||
# or if it is the master project.
|
||||
@@ -9,12 +9,22 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(MASTER_PROJECT ON)
|
||||
endif ()
|
||||
|
||||
# Joins arguments and places the results in ${result_var}.
|
||||
function(join result_var)
|
||||
set(result )
|
||||
foreach (arg ${ARGN})
|
||||
set(result "${result}${arg}")
|
||||
endforeach ()
|
||||
set(${result_var} "${result}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Set the default CMAKE_BUILD_TYPE to Release.
|
||||
# This should be done before the project command since the latter can set
|
||||
# CMAKE_BUILD_TYPE itself (it does so for nmake).
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING
|
||||
"Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
|
||||
join(doc "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or "
|
||||
"CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING ${doc})
|
||||
endif ()
|
||||
|
||||
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
|
||||
@@ -28,13 +38,17 @@ option(FMT_USE_CPP11 "Enable the addition of C++11 compiler flags." ON)
|
||||
project(FMT)
|
||||
|
||||
# Starting with cmake 3.0 VERSION is part of the project command.
|
||||
set(FMT_VERSION 3.0.0)
|
||||
if (NOT FMT_VERSION MATCHES "^([0-9]+).([0-9]+).([0-9]+)$")
|
||||
message(FATAL_ERROR "Invalid version format ${FMT_VERSION}.")
|
||||
file(READ fmt/format.h format_h)
|
||||
if (NOT format_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])")
|
||||
message(FATAL_ERROR "Cannot get FMT_VERSION from format.h.")
|
||||
endif ()
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
|
||||
# Use math to skip leading zeros if any.
|
||||
math(EXPR CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
math(EXPR CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
|
||||
math(EXPR CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
|
||||
join(FMT_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.
|
||||
${CPACK_PACKAGE_VERSION_PATCH})
|
||||
message(STATUS "Version: ${FMT_VERSION}")
|
||||
|
||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Contributing to fmt
|
||||
===================
|
||||
|
||||
All C++ code must adhere to `Google C++ Style Guide
|
||||
<https://google.github.io/styleguide/cppguide.html>`_ with the following
|
||||
exceptions:
|
||||
|
||||
* Exceptions are permitted
|
||||
* snake_case should be used instead of UpperCamelCase for function names
|
||||
|
||||
Thanks for contributing!
|
||||
@@ -1,3 +1,113 @@
|
||||
4.0.0 - 2017-06-27
|
||||
------------------
|
||||
|
||||
* Removed old compatibility headers ``cppformat/*.h`` and CMake options (`#527 <https://github.com/pull/527>`_). Thanks `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_.
|
||||
|
||||
* Added ``string.h`` containing ``fmt::to_string()`` as alternative to ``std::to_string()`` as well as other string writer functionality (`#326 <https://github.com/fmtlib/fmt/issues/326>`_ and `#441 <https://github.com/fmtlib/fmt/pull/441>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include "fmt/string.h"
|
||||
|
||||
std::string answer = fmt::to_string(42);
|
||||
|
||||
Thanks to `@glebov-andrey (Andrey Glebov) <https://github.com/glebov-andrey>`_.
|
||||
|
||||
* Moved ``fmt::printf()`` to new ``printf.h`` header and allowed ``%s`` as generic specifier (`#453 <https://github.com/fmtlib/fmt/pull/453>`_), made ``%.f`` more conformant to regular ``printf()`` (`#490 <https://github.com/fmtlib/fmt/pull/490>`_), added custom writer support (`#476 <https://github.com/fmtlib/fmt/issues/476>`_) and implemented missing custom argument formatting (`#339 <https://github.com/fmtlib/fmt/pull/339>`_ and `#340 <https://github.com/fmtlib/fmt/pull/340>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include "fmt/printf.h"
|
||||
|
||||
// %s format specifier can be used with any argument type.
|
||||
fmt::printf("%s", 42);
|
||||
|
||||
Thanks `@mojoBrendan <https://github.com/mojoBrendan>`_, `@manylegged (Arthur Danskin) <https://github.com/manylegged>`_ and `@spacemoose (Glen Stark) <https://github.com/spacemoose>`_. See also `#360 <https://github.com/fmtlib/fmt/issues/360>`_, `#335 <https://github.com/fmtlib/fmt/issues/335>`_ and `#331 <https://github.com/fmtlib/fmt/issues/331>`_.
|
||||
|
||||
* Added ``container.h`` containing a ``BasicContainerWriter`` to write to containers like ``std::vector`` (`#450 <https://github.com/fmtlib/fmt/pull/450>`_). Thanks `@polyvertex (Jean-Charles Lefebvre) <https://github.com/polyvertex>`_.
|
||||
|
||||
* Added ``fmt::join()`` function that takes a range and formats its elements separated by a given string (`#466 <https://github.com/fmtlib/fmt/pull/466>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
std::vector<double> v = {1.2, 3.4, 5.6};
|
||||
// Prints "(+01.20, +03.40, +05.60)".
|
||||
fmt::print("({:+06.2f})", fmt::join(v.begin(), v.end(), ", "));
|
||||
|
||||
Thanks `@olivier80 <https://github.com/olivier80>`_.
|
||||
|
||||
* Added support for custom formatting specifications to simplify customization of built-in formatting (`#444 <https://github.com/fmtlib/fmt/pull/444>`_). Thanks `@polyvertex (Jean-Charles Lefebvre) <https://github.com/polyvertex>`_. See also `#439 <https://github.com/fmtlib/fmt/issues/439>`_.
|
||||
|
||||
* Added ``fmt::format_system_error()`` for error code formatting (`#323 <https://github.com/fmtlib/fmt/issues/323>`_ and `#526 <https://github.com/fmtlib/fmt/pull/526>`_). Thanks `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_.
|
||||
|
||||
* Added thread-safe ``fmt::localtime()`` and ``fmt::gmtime()`` as replacement for the standard version to ``time.h`` (`#396 <https://github.com/fmtlib/fmt/pull/396>`_). Thanks `@codicodi <https://github.com/codicodi>`_.
|
||||
|
||||
* Internal improvements to ``NamedArg`` and ``ArgLists`` (`#389 <https://github.com/fmtlib/fmt/pull/389>`_ and `#390 <https://github.com/fmtlib/fmt/pull/390>`_). Thanks `@chronoxor <https://github.com/chronoxor>`_.
|
||||
|
||||
* Fixed crash due to bug in ``FormatBuf`` (`#493 <https://github.com/fmtlib/fmt/pull/493>`_). Thanks `@effzeh <https://github.com/effzeh>`_. See also `#480 <https://github.com/fmtlib/fmt/issues/480>`_ and `#491 <https://github.com/fmtlib/fmt/issues/491>`_.
|
||||
|
||||
* Fixed handling of wide strings in ``fmt::StringWriter``.
|
||||
|
||||
* Improved compiler error messages (`#357 <https://github.com/fmtlib/fmt/issues/357>`_).
|
||||
|
||||
* Fixed various warnings and issues with various compilers (`#494 <https://github.com/fmtlib/fmt/pull/494>`_, `#499 <https://github.com/fmtlib/fmt/pull/499>`_, `#483 <https://github.com/fmtlib/fmt/pull/483>`_, `#519 <https://github.com/fmtlib/fmt/pull/519>`_, `#485 <https://github.com/fmtlib/fmt/pull/485>`_, `#482 <https://github.com/fmtlib/fmt/pull/482>`_, `#475 <https://github.com/fmtlib/fmt/pull/475>`_, `#473 <https://github.com/fmtlib/fmt/pull/473>`_ and `#414 <https://github.com/fmtlib/fmt/pull/414>`_). Thanks `@chronoxor <https://github.com/chronoxor>`_, `@zhaohuaxishi <https://github.com/zhaohuaxishi>`_, `@pkestene (Pierre Kestener) <https://github.com/pkestene>`_, `@dschmidt (Dominik Schmidt) <https://github.com/dschmidt>`_ and `@0x414c (Alexey Gorishny) <https://github.com/0x414c>`_ .
|
||||
|
||||
* Improved CMake: targets are now namespaced (`#511 <https://github.com/fmtlib/fmt/pull/511>`_ and `#513 <https://github.com/fmtlib/fmt/pull/513>`_), supported header-only ``printf.h`` (`#354 <https://github.com/fmtlib/fmt/pull/354>`_), fixed issue with minimal supported library subset (`#418 <https://github.com/fmtlib/fmt/issues/418>`_, `#419 <https://github.com/fmtlib/fmt/pull/419>`_ and `#420 <https://github.com/fmtlib/fmt/pull/420>`_). Thanks `@bjoernthiel (Bjoern Thiel) <https://github.com/bjoernthiel>`_,
|
||||
`@niosHD (Mario Werner) <https://github.com/niosHD>`_, `@LogicalKnight (Sean LK) <https://github.com/LogicalKnight>`_ and `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_.
|
||||
|
||||
* Improved documentation. Thanks to `@pwm1234 (Phil) <https://github.com/pwm1234>`_ for `#393 <https://github.com/fmtlib/fmt/pull/393>`_.
|
||||
|
||||
3.0.2 - 2017-06-14
|
||||
------------------
|
||||
|
||||
* Added ``FMT_VERSION`` macro (`#411 <https://github.com/fmtlib/fmt/issues/411>`_).
|
||||
|
||||
* Used ``FMT_NULL`` instead of literal ``0`` (`#409 <https://github.com/fmtlib/fmt/pull/409>`_). Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_.
|
||||
|
||||
* Added extern templates for ``format_float`` (`#413 <https://github.com/fmtlib/fmt/issues/413>`_).
|
||||
|
||||
* Fixed implicit conversion issue (`#507 <https://github.com/fmtlib/fmt/issues/507>`_).
|
||||
|
||||
* Fixed signbit detection (`#423 <https://github.com/fmtlib/fmt/issues/423>`_).
|
||||
|
||||
* Fixed naming collision (`#425 <https://github.com/fmtlib/fmt/issues/425>`_).
|
||||
|
||||
* Fixed missing intrinsic for C++/CLI (`#457 <https://github.com/fmtlib/fmt/pull/457>`_). Thanks `@calumr (Calum Robinson) <https://github.com/calumr>`_
|
||||
|
||||
* Fixed Android detection (`#458 <https://github.com/fmtlib/fmt/pull/458>`_). Thanks `@Gachapen (Magnus Bjerke Vik) <https://github.com/Gachapen>`_.
|
||||
|
||||
* Use lean ``windows.h`` if not in header-only mode (`#503 <https://github.com/fmtlib/fmt/pull/503>`_). Thanks `@Quentin01 (Quentin Buathier) <https://github.com/Quentin01>`_.
|
||||
|
||||
* Fixed issue with CMake exporting C++11 flag (`#445 <https://github.com/fmtlib/fmt/pull/455>`_). Thanks `@EricWF (Eric) <https://github.com/EricWF>`_.
|
||||
|
||||
* Fixed issue with nvcc and MSVC compiler bug and MinGW (`#505 <https://github.com/fmtlib/fmt/issues/505>`_).
|
||||
|
||||
* Fixed DLL issues (`#469 <https://github.com/fmtlib/fmt/pull/469>`_ and `#502 <https://github.com/fmtlib/fmt/pull/502>`_). Thanks `@richardeakin (Richard Eakin) <https://github.com/richardeakin>`_ and `@AndreasSchoenle (Andreas Schönle) <https://github.com/AndreasSchoenle>`_.
|
||||
|
||||
* Fixed test compilation under FreeBSD (`#433 <https://github.com/fmtlib/fmt/issues/433>`_).
|
||||
|
||||
* Fixed various warnings (`#403 <https://github.com/fmtlib/fmt/pull/403>`_, `#410 <https://github.com/fmtlib/fmt/pull/410>`_ and `#510 <https://github.com/fmtlib/fmt/pull/510>`_). Thanks `@Lecetem <https://github.com/Lectem>`_, `@chenhayat (Chen Hayat) <https://github.com/chenhayat>`_ and `@trozen <https://github.com/trozen>`_.
|
||||
|
||||
* Removed redundant include (`#479 <https://github.com/fmtlib/fmt/issues/479>`_).
|
||||
|
||||
* Fixed documentation issues.
|
||||
|
||||
3.0.1 - 2016-11-01
|
||||
------------------
|
||||
* Fixed handling of thousands seperator (`#353 <https://github.com/fmtlib/fmt/issues/353>`_)
|
||||
|
||||
* Fixed handling of ``unsigned char`` strings (`#373 <https://github.com/fmtlib/fmt/issues/373>`_)
|
||||
|
||||
* Corrected buffer growth when formatting time (`#367 <https://github.com/fmtlib/fmt/issues/367>`_)
|
||||
|
||||
* Removed warnings under MSVC and clang (`#318 <https://github.com/fmtlib/fmt/issues/318>`_, `#250 <https://github.com/fmtlib/fmt/issues/250>`_, also merged `#385 <https://github.com/fmtlib/fmt/pull/385>`_ and `#361 <https://github.com/fmtlib/fmt/pull/361>`_). Thanks `@jcelerier (Jean-Michaël Celerier) <https://github.com/jcelerier>`_ and `@nmoehrle (Nils Moehrle) <https://github.com/nmoehrle>`_.
|
||||
|
||||
* Fixed compilation issues under Android (`#327 <https://github.com/fmtlib/fmt/pull/327>`_, `#345 <https://github.com/fmtlib/fmt/issues/345>`_ and `#381 <https://github.com/fmtlib/fmt/pull/381>`_), FreeBSD (`#358 <https://github.com/fmtlib/fmt/pull/358>`_), Cygwin (`#388 <https://github.com/fmtlib/fmt/issues/388>`_), MinGW (`#355 <https://github.com/fmtlib/fmt/issues/355>`_) as well as other issues (`#350 <https://github.com/fmtlib/fmt/issues/350>`_, `#366 <https://github.com/fmtlib/fmt/issues/355>`_, `#348 <https://github.com/fmtlib/fmt/pull/348>`_, `#402 <https://github.com/fmtlib/fmt/pull/402>`_, `#405 <https://github.com/fmtlib/fmt/pull/405>`_). Thanks to `@dpantele (Dmitry) <https://github.com/dpantele>`_, `@hghwng (Hugh Wang) <https://github.com/hghwng>`_, `@arvedarved (Tilman Keskinöz) <https://github.com/arvedarved>`_, `@LogicalKnight (Sean) <https://github.com/LogicalKnight>`_ and `@JanHellwig (Jan Hellwig) <https://github.com/janhellwig>`_.
|
||||
|
||||
* Fixed some documentation issues and extended specification (`#320 <https://github.com/fmtlib/fmt/issues/320>`_, `#333 <https://github.com/fmtlib/fmt/pull/333>`_, `#347 <https://github.com/fmtlib/fmt/issues/347>`_, `#362 <https://github.com/fmtlib/fmt/pull/362>`_). Thanks to `@smellman (Taro Matsuzawa aka. btm) <https://github.com/smellman>`_.
|
||||
|
||||
3.0.0 - 2016-05-07
|
||||
------------------
|
||||
|
||||
|
||||
+28
-5
@@ -20,9 +20,11 @@ alternative to IOStreams.
|
||||
Features
|
||||
--------
|
||||
|
||||
* Two APIs: faster concatenation-based write API and slower (but still
|
||||
very fast) replacement-based format API with positional arguments for
|
||||
localization.
|
||||
* Two APIs: faster concatenation-based `write API
|
||||
<http://fmtlib.net/latest/api.html#write-api>`_ and slower,
|
||||
but still very fast, replacement-based `format API
|
||||
<http://fmtlib.net/latest/api.html#format-api>`_ with positional arguments
|
||||
for localization.
|
||||
* Write API similar to the one used by IOStreams but stateless allowing
|
||||
faster implementation.
|
||||
* Format API with `format string syntax
|
||||
@@ -35,10 +37,10 @@ Features
|
||||
* Support for user-defined types.
|
||||
* High speed: performance of the format API is close to that of
|
||||
glibc's `printf <http://en.cppreference.com/w/cpp/io/c/fprintf>`_
|
||||
and better than performance of IOStreams. See `Speed tests`_ and
|
||||
and better than the performance of IOStreams. See `Speed tests`_ and
|
||||
`Fast integer to string conversion in C++
|
||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
||||
* Small code size both in terms of source code (format consists of a single
|
||||
* Small code size both in terms of source code (the core library consists of a single
|
||||
header file and a single source file) and compiled code.
|
||||
See `Compile time and code bloat`_.
|
||||
* Reliability: the library has an extensive set of `unit tests
|
||||
@@ -89,6 +91,8 @@ An object of any user-defined type for which there is an overloaded
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include "fmt/ostream.h"
|
||||
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
public:
|
||||
@@ -132,6 +136,12 @@ Projects using this library
|
||||
* `AMPL/MP <https://github.com/ampl/mp>`_:
|
||||
An open-source library for mathematical programming
|
||||
|
||||
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater vehicle
|
||||
|
||||
* `Drake <http://drake.mit.edu/>`_: A planning, control, and analysis toolbox for nonlinear dynamical systems (MIT)
|
||||
|
||||
* `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus (Lyft)
|
||||
|
||||
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
||||
Player vs Player Gaming Network with tweaks
|
||||
|
||||
@@ -139,6 +149,8 @@ Projects using this library
|
||||
|
||||
* `Keypirinha <http://keypirinha.com/>`_: A semantic launcher for Windows
|
||||
|
||||
* `Kodi <https://kodi.tv/>`_ (formerly xbmc): Home theater software
|
||||
|
||||
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
|
||||
|
||||
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to generate randomized datasets
|
||||
@@ -158,6 +170,12 @@ Projects using this library
|
||||
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
|
||||
Business intelligence software
|
||||
|
||||
* `Scylla <http://www.scylladb.com/>`_: A Cassandra-compatible NoSQL data store that can handle
|
||||
1 million transactions per second on a single server
|
||||
|
||||
* `Seastar <http://www.seastar-project.org/>`_: An advanced, open-source C++ framework for
|
||||
high-performance server applications on modern hardware
|
||||
|
||||
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
|
||||
|
||||
* `Stellar <https://www.stellar.org/>`_: Financial platform
|
||||
@@ -390,6 +408,11 @@ It only applies if you distribute the documentation of fmt.
|
||||
Acknowledgments
|
||||
---------------
|
||||
|
||||
The fmt library is maintained by Victor Zverovich (`vitaut <https://github.com/vitaut>`_)
|
||||
and Jonathan Müller (`foonathan <https://github.com/foonathan>`_) with contributions from many
|
||||
other people. See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and `Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names. Let us know if your contribution
|
||||
is not listed or mentioned incorrectly and we'll make it right.
|
||||
|
||||
The benchmark section of this readme file and the performance tests are taken
|
||||
from the excellent `tinyformat <https://github.com/c42f/tinyformat>`_ library
|
||||
written by Chris Foster. Boost Format library is acknowledged transitively
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "../fmt/format.h"
|
||||
#warning Including cppformat/format.h is deprecated. Include fmt/format.h instead.
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "../fmt/posix.h"
|
||||
#warning Including cppformat/posix.h is deprecated. Include fmt/posix.h instead.
|
||||
@@ -5,6 +5,8 @@ if (NOT DOXYGEN)
|
||||
endif ()
|
||||
|
||||
add_custom_target(doc
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION})
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION}
|
||||
SOURCES build.py conf.py _templates/layout.html)
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/ DESTINATION share/doc/fmt)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/
|
||||
DESTINATION share/doc/fmt OPTIONAL)
|
||||
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
|
||||
/* -- breathe specific styles ----------------------------------------------- */
|
||||
|
||||
/* So enum value descriptions are displayed inline to the item */
|
||||
.breatheenumvalues li tt + p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* So parameter descriptions are displayed inline to the item */
|
||||
.breatheparameterlist li tt + p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.container .breathe-sectiondef {
|
||||
width: inherit;
|
||||
}
|
||||
|
||||
.github-btn {
|
||||
border: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.jumbotron {
|
||||
background-size: 100% 4px;
|
||||
background-repeat: repeat-y;
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
+31
-20
@@ -8,8 +8,9 @@
|
||||
{# Google Analytics #}
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();
|
||||
a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;
|
||||
a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-20116650-4', 'fmtlib.net');
|
||||
ga('send', 'pageview');
|
||||
@@ -17,9 +18,11 @@
|
||||
{% endblock %}
|
||||
|
||||
{%- macro searchform(classes, button) %}
|
||||
<form class="{{classes}}" role="search" action="{{ pathto('search') }}" method="get">
|
||||
<form class="{{classes}}" role="search" action="{{ pathto('search') }}"
|
||||
method="get">
|
||||
<div class="form-group">
|
||||
<input type="text" name="q" class="form-control" {{ 'placeholder="Search"' if not button }} >
|
||||
<input type="text" name="q" class="form-control"
|
||||
{{ 'placeholder="Search"' if not button }} >
|
||||
</div>
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
@@ -36,7 +39,8 @@
|
||||
<div class="navbar-content">
|
||||
{# Brand and toggle get grouped for better mobile display #}
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -49,18 +53,19 @@
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
{# TODO: update versions automatically #}
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||
aria-expanded="false">{{ version }} <span class="caret"></span></a>
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
|
||||
role="button" aria-expanded="false">{{ version }}
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="http://fmtlib.net/2.0.0/">2.0.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.1.0/">1.1.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.0.0/">1.0.0</a></li>
|
||||
{% for v in versions.split(',') %}
|
||||
<li><a href="http://fmtlib.net/{{v}}">{{v}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% for name in ['Contents', 'Usage', 'API', 'Syntax'] %}
|
||||
{% if pagename == name.lower() %}
|
||||
<li class="active"><a href="{{name.lower()}}.html">{{name}} <span class="sr-only">(current)</span></a></li>
|
||||
<li class="active"><a href="{{name.lower()}}.html">{{name}}
|
||||
<span class="sr-only">(current)</span></a></li>
|
||||
{%else%}
|
||||
<li><a href="{{name.lower()}}.html">{{name}}</a></li>
|
||||
{%endif%}
|
||||
@@ -75,20 +80,25 @@
|
||||
</div> {# /.tb-container #}
|
||||
</nav>
|
||||
{% if pagename == "index" %}
|
||||
{% set download_url = 'https://github.com/fmtlib/fmt/releases/download' %}
|
||||
<div class="jumbotron">
|
||||
<div class="tb-container">
|
||||
<h1>{fmt}</h1>
|
||||
<p class="lead">Small, safe and fast formatting library</p>
|
||||
<div class="btn-group" role="group">
|
||||
{% set name = 'fmt' if version.split('.')[0]|int >= 3 else 'cppformat' %}
|
||||
<a class="btn btn-success"
|
||||
href="https://github.com/fmtlib/fmt/releases/download/2.0.0/cppformat-2.0.0.zip">
|
||||
<span class="glyphicon glyphicon-download"></span> Download
|
||||
href="{{download_url}}/{{version}}/{{name}}-{{version}}.zip">
|
||||
<span class="glyphicon glyphicon-download"></span> Download
|
||||
</a>
|
||||
<button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
|
||||
<button type="button" class="btn btn-success dropdown-toggle"
|
||||
data-toggle="dropdown"><span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="https://github.com/fmtlib/fmt/releases/download/2.0.0/cppformat-2.0.0.zip">Version 2.0.0</a></li>
|
||||
<li><a href="https://github.com/fmtlib/fmt/releases/download/1.1.0/cppformat-1.1.0.zip">Version 1.1.0</a></li>
|
||||
<li><a href="https://github.com/fmtlib/fmt/releases/download/1.0.0/cppformat-1.0.0.zip">Version 1.0.0</a></li>
|
||||
{% for v in versions.split(',') %}
|
||||
{% set name = 'fmt' if v.split('.')[0]|int >= 3 else 'cppformat' %}
|
||||
<li><a href="{{download_url}}/{{v}}/{{name}}-{{v}}.zip">Version {{v}}
|
||||
</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -105,14 +115,15 @@
|
||||
{% block content %}
|
||||
<div class="tb-container">
|
||||
<div class="row">
|
||||
{# TODO: integrate sidebar
|
||||
{# Sidebar is currently disabled.
|
||||
<div class="bs-sidebar">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
{%- block sidebarlogo %}
|
||||
{%- if logo %}
|
||||
<p class="logo"><a href="{{ pathto(master_doc) }}">
|
||||
<img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
|
||||
<img class="logo" src="{{ pathto('_static/' + logo, 1) }}"
|
||||
alt="Logo"/>
|
||||
</a></p>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
|
||||
+78
-12
@@ -11,8 +11,8 @@ namespace is usually omitted in examples.
|
||||
Format API
|
||||
==========
|
||||
|
||||
The following functions use :ref:`format string syntax <syntax>` similar
|
||||
to the one used by Python's `str.format
|
||||
The following functions defined in ``fmt/format.h`` use :ref:`format string
|
||||
syntax <syntax>` similar to the one used by Python's `str.format
|
||||
<http://docs.python.org/3/library/stdtypes.html#str.format>`_ function.
|
||||
They take *format_str* and *args* as arguments.
|
||||
|
||||
@@ -22,6 +22,11 @@ arguments in the resulting string.
|
||||
|
||||
*args* is an argument list representing arbitrary arguments.
|
||||
|
||||
The `performance of the format API
|
||||
<https://github.com/fmtlib/fmt/blob/master/README.rst#speed-tests>`_ is close
|
||||
to that of glibc's ``printf`` and better than the performance of IOStreams.
|
||||
For even better speed use the `write API`_.
|
||||
|
||||
.. _format:
|
||||
|
||||
.. doxygenfunction:: format(CStringRef, ArgList)
|
||||
@@ -40,8 +45,9 @@ arguments in the resulting string.
|
||||
Date and time formatting
|
||||
------------------------
|
||||
|
||||
The library supports `strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like
|
||||
date and time formatting::
|
||||
The library supports `strftime
|
||||
<http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like date and time
|
||||
formatting::
|
||||
|
||||
#include "fmt/time.h"
|
||||
|
||||
@@ -52,6 +58,36 @@ date and time formatting::
|
||||
The format string syntax is described in the documentation of
|
||||
`strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_.
|
||||
|
||||
Formatting user-defined types
|
||||
-----------------------------
|
||||
|
||||
A custom ``format_arg`` function may be implemented and used to format any
|
||||
user-defined type. That is how date and time formatting described in the
|
||||
previous section is implemented in :file:`fmt/time.h`. The following example
|
||||
shows how to implement custom formatting for a user-defined structure.
|
||||
|
||||
::
|
||||
|
||||
struct MyStruct { double a, b; };
|
||||
|
||||
void format_arg(fmt::BasicFormatter<char> &f,
|
||||
const char *&format_str, const MyStruct &s) {
|
||||
f.writer().write("[MyStruct: a={:.1f}, b={:.2f}]", s.a, s.b);
|
||||
}
|
||||
|
||||
MyStruct m = { 1, 2 };
|
||||
std::string s = fmt::format("m={}", n);
|
||||
// s == "m=[MyStruct: a=1.0, b=2.00]"
|
||||
|
||||
Note in the example above the ``format_arg`` function ignores the contents of
|
||||
``format_str`` so the type will always be formatted as specified. See
|
||||
``format_arg`` in :file:`fmt/time.h` for an advanced example of how to use
|
||||
the ``format_str`` argument to customize the formatted output.
|
||||
|
||||
This section shows how to define a custom format function for a user-defined
|
||||
type. The next section describes how to get ``fmt`` to use a conventional stream
|
||||
output ``operator<<`` when one is defined for a user-defined type.
|
||||
|
||||
``std::ostream`` support
|
||||
------------------------
|
||||
|
||||
@@ -63,7 +99,7 @@ formatting of user-defined types that have overloaded ``operator<<``::
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
public:
|
||||
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
|
||||
Date(int year, int month, int day): year_(year), month_(month), day_(day) {}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const Date &d) {
|
||||
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
|
||||
@@ -75,8 +111,6 @@ formatting of user-defined types that have overloaded ``operator<<``::
|
||||
|
||||
.. doxygenfunction:: print(std::ostream&, CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList)
|
||||
|
||||
Argument formatters
|
||||
-------------------
|
||||
|
||||
@@ -86,7 +120,7 @@ custom argument formatter class::
|
||||
// A custom argument formatter that formats negative integers as unsigned
|
||||
// with the ``x`` format specifier.
|
||||
class CustomArgFormatter :
|
||||
public fmt::BasicArgFormatter<CustomArgFormatter, char> {
|
||||
public fmt::BasicArgFormatter<CustomArgFormatter, char> {
|
||||
public:
|
||||
CustomArgFormatter(fmt::BasicFormatter<char, CustomArgFormatter> &f,
|
||||
fmt::FormatSpec &s, const char *fmt)
|
||||
@@ -120,22 +154,43 @@ custom argument formatter class::
|
||||
.. doxygenclass:: fmt::ArgFormatter
|
||||
:members:
|
||||
|
||||
Printf formatting functions
|
||||
---------------------------
|
||||
Printf formatting
|
||||
-----------------
|
||||
|
||||
The header ``fmt/printf.h`` provides ``printf``-like formatting functionality.
|
||||
The following functions use `printf format string syntax
|
||||
<http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>`_ with
|
||||
a POSIX extension for positional arguments.
|
||||
the POSIX extension for positional arguments. Unlike their standard
|
||||
counterparts, the ``fmt`` functions are type-safe and throw an exception if an
|
||||
argument type doesn't match its format specification.
|
||||
|
||||
.. doxygenfunction:: printf(CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fprintf(std::FILE *, CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: sprintf(CStringRef, ArgList)
|
||||
|
||||
.. doxygenclass:: fmt::PrintfFormatter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicPrintfArgFormatter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::PrintfArgFormatter
|
||||
:members:
|
||||
|
||||
Write API
|
||||
=========
|
||||
|
||||
The write API provides classes for writing formatted data into character
|
||||
streams. It is usually faster than the `format API`_ but, as IOStreams,
|
||||
may result in larger compiled code size. The main writer class is
|
||||
`~fmt::BasicMemoryWriter` which stores its output in a memory buffer and
|
||||
provides direct access to it. It is possible to create custom writers that
|
||||
store output elsewhere by subclassing `~fmt::BasicWriter`.
|
||||
|
||||
.. doxygenclass:: fmt::BasicWriter
|
||||
:members:
|
||||
|
||||
@@ -145,6 +200,12 @@ Write API
|
||||
.. doxygenclass:: fmt::BasicArrayWriter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicStringWriter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicContainerWriter
|
||||
:members:
|
||||
|
||||
.. doxygenfunction:: bin(int)
|
||||
|
||||
.. doxygenfunction:: oct(int)
|
||||
@@ -169,6 +230,8 @@ Utilities
|
||||
.. doxygenclass:: fmt::ArgList
|
||||
:members:
|
||||
|
||||
.. doxygenfunction:: fmt::to_string(const T&)
|
||||
|
||||
.. doxygenclass:: fmt::BasicStringRef
|
||||
:members:
|
||||
|
||||
@@ -185,6 +248,8 @@ System errors
|
||||
.. doxygenclass:: fmt::SystemError
|
||||
:members:
|
||||
|
||||
.. doxygenfunction:: fmt::format_system_error
|
||||
|
||||
.. doxygenclass:: fmt::WindowsError
|
||||
:members:
|
||||
|
||||
@@ -202,7 +267,8 @@ A custom allocator class can be specified as a template argument to
|
||||
It is also possible to write a formatting function that uses a custom
|
||||
allocator::
|
||||
|
||||
typedef std::basic_string<char, std::char_traits<char>, CustomAllocator> CustomString;
|
||||
typedef std::basic_string<char, std::char_traits<char>, CustomAllocator>
|
||||
CustomString;
|
||||
|
||||
CustomString format(CustomAllocator alloc, fmt::CStringRef format_str,
|
||||
fmt::ArgList args) {
|
||||
|
||||
@@ -90,7 +90,8 @@
|
||||
VERSION: '{{ release|e }}',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
|
||||
HAS_SOURCE: {{ has_source|lower }}
|
||||
HAS_SOURCE: {{ has_source|lower }},
|
||||
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
|
||||
};
|
||||
</script>
|
||||
{%- for scriptfile in script_files %}
|
||||
|
||||
+46
-28
@@ -8,30 +8,35 @@ from distutils.version import LooseVersion
|
||||
|
||||
def pip_install(package, commit=None, **kwargs):
|
||||
"Install package using pip."
|
||||
min_version = kwargs.get('min_version')
|
||||
if min_version:
|
||||
from pkg_resources import get_distribution, DistributionNotFound
|
||||
try:
|
||||
installed_version = get_distribution(os.path.basename(package)).version
|
||||
if LooseVersion(installed_version) >= min_version:
|
||||
print('{} {} already installed'.format(package, min_version))
|
||||
return
|
||||
except DistributionNotFound:
|
||||
pass
|
||||
if commit:
|
||||
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)
|
||||
print('Installing {}'.format(package))
|
||||
check_call(['pip', 'install', '--upgrade', package])
|
||||
package = 'git+https://github.com/{0}.git@{1}'.format(package, commit)
|
||||
print('Installing {0}'.format(package))
|
||||
check_call(['pip', 'install', package])
|
||||
|
||||
def build_docs(version='dev'):
|
||||
def create_build_env(dirname='virtualenv'):
|
||||
# Create virtualenv.
|
||||
doc_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
virtualenv_dir = 'virtualenv'
|
||||
check_call(['virtualenv', virtualenv_dir])
|
||||
if not os.path.exists(dirname):
|
||||
check_call(['virtualenv', dirname])
|
||||
import sysconfig
|
||||
scripts_dir = os.path.basename(sysconfig.get_path('scripts'))
|
||||
activate_this_file = os.path.join(virtualenv_dir, scripts_dir,
|
||||
'activate_this.py')
|
||||
activate_this_file = os.path.join(dirname, scripts_dir, 'activate_this.py')
|
||||
with open(activate_this_file) as f:
|
||||
exec(f.read(), dict(__file__=activate_this_file))
|
||||
# Import get_distribution after activating virtualenv to get info about
|
||||
# the correct packages.
|
||||
from pkg_resources import get_distribution, DistributionNotFound
|
||||
# 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")
|
||||
@@ -46,27 +51,35 @@ def build_docs(version='dev'):
|
||||
except DistributionNotFound:
|
||||
pass
|
||||
# Install Sphinx and Breathe.
|
||||
pip_install('fmtlib/sphinx',
|
||||
'12dde8afdb0a7bb5576e2656692c3478c69d8cc3',
|
||||
check_version='1.4a0.dev-20151013')
|
||||
pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee',
|
||||
min_version='1.4.1.dev20160531')
|
||||
pip_install('michaeljones/breathe',
|
||||
'1c9d7f80378a92cffa755084823a78bb38ee4acc')
|
||||
'6b1c5bb7a1866f15fc328b8716258354b10c1daa',
|
||||
min_version='4.2.0')
|
||||
|
||||
def build_docs(version='dev', **kwargs):
|
||||
doc_dir = kwargs.get('doc_dir', os.path.dirname(os.path.realpath(__file__)))
|
||||
work_dir = kwargs.get('work_dir', '.')
|
||||
include_dir = kwargs.get('include_dir',
|
||||
os.path.join(os.path.dirname(doc_dir), 'fmt'))
|
||||
# Build docs.
|
||||
cmd = ['doxygen', '-']
|
||||
p = Popen(cmd, stdin=PIPE)
|
||||
doxyxml_dir = os.path.join(work_dir, 'doxyxml')
|
||||
p.communicate(input=r'''
|
||||
PROJECT_NAME = fmt
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_MAN = NO
|
||||
GENERATE_RTF = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
INPUT = {0}/format.h {0}/ostream.h
|
||||
INPUT = {0}/container.h {0}/format.h {0}/ostream.h \
|
||||
{0}/printf.h {0}/string.h
|
||||
QUIET = YES
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
AUTOLINK_SUPPORT = NO
|
||||
GENERATE_HTML = NO
|
||||
GENERATE_XML = YES
|
||||
XML_OUTPUT = doxyxml
|
||||
XML_OUTPUT = {1}
|
||||
ALIASES = "rst=\verbatim embed:rst"
|
||||
ALIASES += "endrst=\endverbatim"
|
||||
MACRO_EXPANSION = YES
|
||||
@@ -76,24 +89,29 @@ def build_docs(version='dev'):
|
||||
FMT_USE_USER_DEFINED_LITERALS=1 \
|
||||
FMT_API=
|
||||
EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str
|
||||
'''.format(os.path.join(os.path.dirname(doc_dir), 'fmt')).encode('UTF-8'))
|
||||
'''.format(include_dir, doxyxml_dir).encode('UTF-8'))
|
||||
if p.returncode != 0:
|
||||
raise CalledProcessError(p.returncode, cmd)
|
||||
html_dir = os.path.join(work_dir, 'html')
|
||||
versions = ['3.0.0', '2.0.0', '1.1.0']
|
||||
check_call(['sphinx-build',
|
||||
'-Dbreathe_projects.format=' + os.path.join(os.getcwd(), 'doxyxml'),
|
||||
'-Dversion=' + version, '-Drelease=' + version, '-Aversion=' + version,
|
||||
'-b', 'html', doc_dir, 'html'])
|
||||
'-Dbreathe_projects.format=' + os.path.abspath(doxyxml_dir),
|
||||
'-Dversion=' + version, '-Drelease=' + version,
|
||||
'-Aversion=' + version, '-Aversions=' + ','.join(versions),
|
||||
'-b', 'html', doc_dir, html_dir])
|
||||
try:
|
||||
check_call(['lessc', '--clean-css',
|
||||
'--include-path=' + os.path.join(doc_dir, 'bootstrap'),
|
||||
os.path.join(doc_dir, 'fmt.less'),
|
||||
'html/_static/fmt.css'])
|
||||
os.path.join(html_dir, '_static', 'fmt.css')])
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
print('lessc not found; make sure that Less (http://lesscss.org/) is installed')
|
||||
print('lessc not found; make sure that Less (http://lesscss.org/) ' +
|
||||
'is installed')
|
||||
sys.exit(1)
|
||||
return 'html'
|
||||
return html_dir
|
||||
|
||||
if __name__ == '__main__':
|
||||
create_build_env()
|
||||
build_docs(sys.argv[1])
|
||||
|
||||
@@ -228,8 +228,7 @@ latex_documents = [
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'format', u'format Documentation',
|
||||
[u'Victor Zverovich'], 1)
|
||||
('index', 'fmt', u'fmt documentation', [u'Victor Zverovich'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
@@ -242,8 +241,8 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'format', u'format Documentation',
|
||||
u'Victor Zverovich', 'format', 'One line description of project.',
|
||||
('index', 'fmt', u'fmt documentation',
|
||||
u'Victor Zverovich', 'fmt', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace is usually omitted in examples.
|
||||
Format API
|
||||
==========
|
||||
|
||||
The following functions use :ref:`format string syntax <syntax>` similar
|
||||
to the one used by Python's `str.format
|
||||
The following functions defined in ``fmt/format.h`` use :ref:`format string
|
||||
syntax <syntax>` similar to the one used by Python's `str.format
|
||||
<http://docs.python.org/3/library/stdtypes.html#str.format>`_ function.
|
||||
They take *format_str* and *args* as arguments.
|
||||
|
||||
@@ -22,6 +22,11 @@ arguments in the resulting string.
|
||||
|
||||
*args* is an argument list representing arbitrary arguments.
|
||||
|
||||
The `performance of the format API
|
||||
<https://github.com/fmtlib/fmt/blob/master/README.rst#speed-tests>`_ is close
|
||||
to that of glibc's ``printf`` and better than the performance of IOStreams.
|
||||
For even better speed use the `write API`_.
|
||||
|
||||
.. _format:
|
||||
|
||||
.. doxygenfunction:: format(CStringRef, ArgList)
|
||||
@@ -40,8 +45,9 @@ arguments in the resulting string.
|
||||
Date and time formatting
|
||||
------------------------
|
||||
|
||||
The library supports `strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like
|
||||
date and time formatting::
|
||||
The library supports `strftime
|
||||
<http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like date and time
|
||||
formatting::
|
||||
|
||||
#include "fmt/time.h"
|
||||
|
||||
@@ -52,6 +58,36 @@ date and time formatting::
|
||||
The format string syntax is described in the documentation of
|
||||
`strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_.
|
||||
|
||||
Formatting user-defined types
|
||||
-----------------------------
|
||||
|
||||
A custom ``format_arg`` function may be implemented and used to format any
|
||||
user-defined type. That is how date and time formatting described in the
|
||||
previous section is implemented in :file:`fmt/time.h`. The following example
|
||||
shows how to implement custom formatting for a user-defined structure.
|
||||
|
||||
::
|
||||
|
||||
struct MyStruct { double a, b; };
|
||||
|
||||
void format_arg(fmt::BasicFormatter<char> &f,
|
||||
const char *&format_str, const MyStruct &s) {
|
||||
f.writer().write("[MyStruct: a={:.1f}, b={:.2f}]", s.a, s.b);
|
||||
}
|
||||
|
||||
MyStruct m = { 1, 2 };
|
||||
std::string s = fmt::format("m={}", n);
|
||||
// s == "m=[MyStruct: a=1.0, b=2.00]"
|
||||
|
||||
Note in the example above the ``format_arg`` function ignores the contents of
|
||||
``format_str`` so the type will always be formatted as specified. See
|
||||
``format_arg`` in :file:`fmt/time.h` for an advanced example of how to use
|
||||
the ``format_str`` argument to customize the formatted output.
|
||||
|
||||
This section shows how to define a custom format function for a user-defined
|
||||
type. The next section describes how to get ``fmt`` to use a conventional stream
|
||||
output ``operator<<`` when one is defined for a user-defined type.
|
||||
|
||||
``std::ostream`` support
|
||||
------------------------
|
||||
|
||||
@@ -63,7 +99,7 @@ formatting of user-defined types that have overloaded ``operator<<``::
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
public:
|
||||
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
|
||||
Date(int year, int month, int day): year_(year), month_(month), day_(day) {}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const Date &d) {
|
||||
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
|
||||
@@ -75,8 +111,6 @@ formatting of user-defined types that have overloaded ``operator<<``::
|
||||
|
||||
.. doxygenfunction:: print(std::ostream&, CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList)
|
||||
|
||||
Argument formatters
|
||||
-------------------
|
||||
|
||||
@@ -86,7 +120,7 @@ custom argument formatter class::
|
||||
// A custom argument formatter that formats negative integers as unsigned
|
||||
// with the ``x`` format specifier.
|
||||
class CustomArgFormatter :
|
||||
public fmt::BasicArgFormatter<CustomArgFormatter, char> {
|
||||
public fmt::BasicArgFormatter<CustomArgFormatter, char> {
|
||||
public:
|
||||
CustomArgFormatter(fmt::BasicFormatter<char, CustomArgFormatter> &f,
|
||||
fmt::FormatSpec &s, const char *fmt)
|
||||
@@ -120,22 +154,43 @@ custom argument formatter class::
|
||||
.. doxygenclass:: fmt::ArgFormatter
|
||||
:members:
|
||||
|
||||
Printf formatting functions
|
||||
---------------------------
|
||||
Printf formatting
|
||||
-----------------
|
||||
|
||||
The header ``fmt/printf.h`` provides ``printf``-like formatting functionality.
|
||||
The following functions use `printf format string syntax
|
||||
<http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>`_ with
|
||||
a POSIX extension for positional arguments.
|
||||
the POSIX extension for positional arguments. Unlike their standard
|
||||
counterparts, the ``fmt`` functions are type-safe and throw an exception if an
|
||||
argument type doesn't match its format specification.
|
||||
|
||||
.. doxygenfunction:: printf(CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fprintf(std::FILE *, CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: sprintf(CStringRef, ArgList)
|
||||
|
||||
.. doxygenclass:: fmt::PrintfFormatter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicPrintfArgFormatter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::PrintfArgFormatter
|
||||
:members:
|
||||
|
||||
Write API
|
||||
=========
|
||||
|
||||
The write API provides classes for writing formatted data into character
|
||||
streams. It is usually faster than the `format API`_ but, as IOStreams,
|
||||
may result in larger compiled code size. The main writer class is
|
||||
`~fmt::BasicMemoryWriter` which stores its output in a memory buffer and
|
||||
provides direct access to it. It is possible to create custom writers that
|
||||
store output elsewhere by subclassing `~fmt::BasicWriter`.
|
||||
|
||||
.. doxygenclass:: fmt::BasicWriter
|
||||
:members:
|
||||
|
||||
@@ -145,6 +200,12 @@ Write API
|
||||
.. doxygenclass:: fmt::BasicArrayWriter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicStringWriter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicContainerWriter
|
||||
:members:
|
||||
|
||||
.. doxygenfunction:: bin(int)
|
||||
|
||||
.. doxygenfunction:: oct(int)
|
||||
@@ -169,6 +230,8 @@ Utilities
|
||||
.. doxygenclass:: fmt::ArgList
|
||||
:members:
|
||||
|
||||
.. doxygenfunction:: fmt::to_string(const T&)
|
||||
|
||||
.. doxygenclass:: fmt::BasicStringRef
|
||||
:members:
|
||||
|
||||
@@ -185,6 +248,8 @@ System errors
|
||||
.. doxygenclass:: fmt::SystemError
|
||||
:members:
|
||||
|
||||
.. doxygenfunction:: fmt::format_system_error
|
||||
|
||||
.. doxygenclass:: fmt::WindowsError
|
||||
:members:
|
||||
|
||||
@@ -202,7 +267,8 @@ A custom allocator class can be specified as a template argument to
|
||||
It is also possible to write a formatting function that uses a custom
|
||||
allocator::
|
||||
|
||||
typedef std::basic_string<char, std::char_traits<char>, CustomAllocator> CustomString;
|
||||
typedef std::basic_string<char, std::char_traits<char>, CustomAllocator>
|
||||
CustomString;
|
||||
|
||||
CustomString format(CustomAllocator alloc, fmt::CStringRef format_str,
|
||||
fmt::ArgList args) {
|
||||
|
||||
@@ -10,9 +10,9 @@ alternative to C++ IOStreams.
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">What users say:</div>
|
||||
<div class="panel-body">
|
||||
Thanks for creating this library. It’s been a hole in C++ for a long time.
|
||||
I’ve used both boost::format and loki::SPrintf, and neither felt like the
|
||||
right answer. This does.
|
||||
Thanks for creating this library. It’s been a hole in C++ for a long
|
||||
time. I’ve used both boost::format and loki::SPrintf, and neither felt
|
||||
like the right answer. This does.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,8 +24,8 @@ Format API
|
||||
The replacement-based Format API provides a safe alternative to ``printf``,
|
||||
``sprintf`` and friends with comparable or `better performance
|
||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
||||
The `format string syntax <doc/latest/index.html#format-string-syntax>`_ is similar
|
||||
to the one used by `str.format <http://docs.python.org/2/library/stdtypes.html#str.format>`_
|
||||
The `format string syntax <syntax.html>`_ is similar to the one used by
|
||||
`str.format <http://docs.python.org/2/library/stdtypes.html#str.format>`_
|
||||
in Python:
|
||||
|
||||
.. code:: c++
|
||||
@@ -98,8 +98,8 @@ literal operators, they must be made visible with the directive
|
||||
Write API
|
||||
---------
|
||||
|
||||
The concatenation-based Write API (experimental) provides a
|
||||
`fast <http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_
|
||||
The concatenation-based Write API (experimental) provides a `fast
|
||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_
|
||||
stateless alternative to IOStreams:
|
||||
|
||||
.. code:: c++
|
||||
@@ -112,8 +112,9 @@ stateless alternative to IOStreams:
|
||||
Safety
|
||||
------
|
||||
|
||||
The library is fully type safe, automatic memory management prevents buffer overflow,
|
||||
errors in format strings are reported using exceptions. For example, the code
|
||||
The library is fully type safe, automatic memory management prevents buffer
|
||||
overflow, errors in format strings are reported using exceptions. For example,
|
||||
the code
|
||||
|
||||
.. code:: c++
|
||||
|
||||
@@ -138,19 +139,21 @@ formatted into a narrow string. You can use a wide format string instead:
|
||||
fmt::format(L"Cyrillic letter {}", L'\x42e');
|
||||
|
||||
For comparison, writing a wide character to ``std::ostream`` results in
|
||||
its numeric value being written to the stream (i.e. 1070 instead of letter 'ю' which
|
||||
is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is needed.
|
||||
its numeric value being written to the stream (i.e. 1070 instead of letter 'ю'
|
||||
which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is
|
||||
needed.
|
||||
|
||||
.. _portability:
|
||||
|
||||
Portability
|
||||
-----------
|
||||
|
||||
The library is highly portable. Here is an incomplete list of operating systems and
|
||||
compilers where it has been tested and known to work:
|
||||
The library is highly portable. Here is an incomplete list of operating systems
|
||||
and compilers where it has been tested and known to work:
|
||||
|
||||
* 64-bit (amd64) GNU/Linux with GCC 4.4.3, `4.6.3 <https://travis-ci.org/fmtlib/fmt>`_,
|
||||
4.7.2, 4.8.1 and Intel C++ Compiler (ICC) 14.0.2
|
||||
* 64-bit (amd64) GNU/Linux with GCC 4.4.3,
|
||||
`4.6.3 <https://travis-ci.org/fmtlib/fmt>`_, 4.7.2, 4.8.1, and Intel C++
|
||||
Compiler (ICC) 14.0.2
|
||||
|
||||
* 32-bit (i386) GNU/Linux with GCC 4.4.3, 4.6.3
|
||||
|
||||
@@ -161,21 +164,21 @@ compilers where it has been tested and known to work:
|
||||
|
||||
* 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. The only thing to keep in mind
|
||||
for C++98 portability:
|
||||
Although the library uses C++11 features when available, it also works with
|
||||
older 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.
|
||||
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
|
||||
* 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
|
||||
of ``printf`` is platform-dependent in this case. For example,
|
||||
The output of all formatting functions is consistent across platforms. In
|
||||
particular, formatting a floating-point infinity always gives ``inf`` while the
|
||||
output of ``printf`` is platform-dependent in this case. For example,
|
||||
|
||||
.. code::
|
||||
|
||||
@@ -188,10 +191,10 @@ always prints ``inf``.
|
||||
Ease of Use
|
||||
-----------
|
||||
|
||||
fmt has a small self-contained code base consisting of a single header file
|
||||
and a single source file and no external dependencies. A permissive BSD `license
|
||||
<https://github.com/fmtlib/fmt#license>`_ allows using the library both
|
||||
in open-source and commercial projects.
|
||||
fmt has a small self-contained code base with the core library consisting of
|
||||
a single header file and a single source file and no external dependencies.
|
||||
A permissive BSD `license <https://github.com/fmtlib/fmt#license>`_ allows
|
||||
using the library both in open-source and commercial projects.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
|
||||
@@ -49,12 +49,10 @@ mini-language" or interpretation of the *format_spec*.
|
||||
Most built-in types support a common formatting mini-language, which is
|
||||
described in the next section.
|
||||
|
||||
A *format_spec* field can also include nested replacement fields within it.
|
||||
These nested replacement fields can contain only an argument index;
|
||||
format specifications are not allowed. Formatting is performed as if the
|
||||
replacement fields within the format_spec are substituted before the
|
||||
*format_spec* string is interpreted. This allows the formatting of a value
|
||||
to be dynamically specified.
|
||||
A *format_spec* field can also include nested replacement fields in certain
|
||||
positions within it. These nested replacement fields can contain only an
|
||||
argument id; format specifications are not allowed. This allows the
|
||||
formatting of a value to be dynamically specified.
|
||||
|
||||
See the :ref:`formatexamples` section for some examples.
|
||||
|
||||
@@ -80,8 +78,8 @@ The general form of a *standard format specifier* is:
|
||||
sign: "+" | "-" | " "
|
||||
width: `integer` | "{" `arg_id` "}"
|
||||
precision: `integer` | "{" `arg_id` "}"
|
||||
type: `int_type` | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
|
||||
int_type: "b" | "B" | "d" | "o" | "x" | "X"
|
||||
type: `int_type` | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
|
||||
int_type: "b" | "B" | "d" | "n" | "o" | "x" | "X"
|
||||
|
||||
The *fill* character can be any character other than '{' or '}'. The presence
|
||||
of a fill character is signaled by the character following it, which must be
|
||||
@@ -234,7 +232,7 @@ The available presentation types for floating-point values are:
|
||||
+=========+==========================================================+
|
||||
| ``'a'`` | Hexadecimal floating point format. Prints the number in |
|
||||
| | base 16 with prefix ``"0x"`` and lower-case letters for |
|
||||
| | digits above 9. Uses 'p' to indicate the exponent. |
|
||||
| | digits above 9. Uses ``'p'`` to indicate the exponent. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'A'`` | Same as ``'a'`` except it uses upper-case letters for |
|
||||
| | the prefix, digits above 9 and to indicate the exponent. |
|
||||
|
||||
@@ -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
|
||||
|
||||
Header-only usage with CMake
|
||||
============================
|
||||
|
||||
In order to add ``fmtlib`` into an existing ``CMakeLists.txt`` file, you can add the ``fmt`` library directory into your main project, which will enable the ``fmt`` library::
|
||||
|
||||
add_subdirectory(fmt)
|
||||
|
||||
If you have a project called ``foo`` that you would like to link against the fmt library in a header-only fashion, you can enable with with::
|
||||
|
||||
target_link_libraries(foo PRIVATE fmt::fmt-header-only)
|
||||
|
||||
And then to ensure that the ``fmt`` library does not always get built, you can modify the call to ``add_subdirectory`` to read ::
|
||||
|
||||
add_subdirectory(fmt EXCLUDE_FROM_ALL)
|
||||
|
||||
This will ensure that the ``fmt`` library is exluded from calls to ``make``, ``make all``, or ``cmake --build .``.
|
||||
|
||||
Building the documentation
|
||||
==========================
|
||||
|
||||
@@ -62,7 +79,11 @@ 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
|
||||
* `Less <http://lesscss.org/>`_ with ``less-plugin-clean-css``.
|
||||
Ubuntu doesn't package the ``clean-css`` plugin so you should use ``npm``
|
||||
instead of ``apt`` to install both ``less`` and the plugin::
|
||||
|
||||
sudo npm install -g less 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::
|
||||
@@ -87,4 +108,4 @@ Homebrew
|
||||
|
||||
fmt can be installed on OS X using `Homebrew <http://brew.sh/>`_::
|
||||
|
||||
brew install cppformat
|
||||
brew install fmt
|
||||
|
||||
@@ -47,8 +47,10 @@
|
||||
.highlight .mh { color: #208050 } /* Literal.Number.Hex */
|
||||
.highlight .mi { color: #208050 } /* Literal.Number.Integer */
|
||||
.highlight .mo { color: #208050 } /* Literal.Number.Oct */
|
||||
.highlight .sa { color: #4070a0 } /* Literal.String.Affix */
|
||||
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
|
||||
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
|
||||
.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */
|
||||
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
|
||||
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
|
||||
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
|
||||
@@ -59,7 +61,9 @@
|
||||
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
|
||||
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
|
||||
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
|
||||
.highlight .fm { color: #06287e } /* Name.Function.Magic */
|
||||
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
|
||||
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
|
||||
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
|
||||
.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */
|
||||
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
|
||||
+405
-132
@@ -8,7 +8,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
|
||||
<title>API Reference — fmt 3.0.0 documentation</title>
|
||||
<title>API Reference — fmt 4.0.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@@ -17,10 +17,11 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: './',
|
||||
VERSION: '3.0.0',
|
||||
VERSION: '4.0.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
HAS_SOURCE: true,
|
||||
SOURCELINK_SUFFIX: ''
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
@@ -35,8 +36,9 @@
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();
|
||||
a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;
|
||||
a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-20116650-4', 'fmtlib.net');
|
||||
ga('send', 'pageview');
|
||||
@@ -50,7 +52,8 @@
|
||||
<div class="navbar-content">
|
||||
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -63,13 +66,17 @@
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||
aria-expanded="false">3.0.0 <span class="caret"></span></a>
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
|
||||
role="button" aria-expanded="false">4.0.0
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="http://fmtlib.net/2.0.0/">2.0.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.1.0/">1.1.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.0.0/">1.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/3.0.0">3.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/2.0.0">2.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/1.1.0">1.1.0</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -82,7 +89,8 @@
|
||||
|
||||
|
||||
|
||||
<li class="active"><a href="api.html">API <span class="sr-only">(current)</span></a></li>
|
||||
<li class="active"><a href="api.html">API
|
||||
<span class="sr-only">(current)</span></a></li>
|
||||
|
||||
|
||||
|
||||
@@ -92,9 +100,11 @@
|
||||
</ul>
|
||||
|
||||
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html" method="get">
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html"
|
||||
method="get">
|
||||
<div class="form-group">
|
||||
<input type="text" name="q" class="form-control" placeholder="Search" >
|
||||
<input type="text" name="q" class="form-control"
|
||||
placeholder="Search" >
|
||||
</div>
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
@@ -122,13 +132,16 @@ in namespace <code class="docutils literal"><span class="pre">fmt</span></code>
|
||||
namespace is usually omitted in examples.</p>
|
||||
<div class="section" id="format-api">
|
||||
<h2>Format API<a class="headerlink" href="#format-api" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The following functions use <a class="reference internal" href="syntax.html#syntax"><span class="std std-ref">format string syntax</span></a> similar
|
||||
to the one used by Python’s <a class="reference external" href="http://docs.python.org/3/library/stdtypes.html#str.format">str.format</a> function.
|
||||
<p>The following functions defined in <code class="docutils literal"><span class="pre">fmt/format.h</span></code> use <a class="reference internal" href="syntax.html#syntax"><span class="std std-ref">format string
|
||||
syntax</span></a> similar to the one used by Python’s <a class="reference external" href="http://docs.python.org/3/library/stdtypes.html#str.format">str.format</a> function.
|
||||
They take <em>format_str</em> and <em>args</em> as arguments.</p>
|
||||
<p><em>format_str</em> is a format string that contains literal text and replacement
|
||||
fields surrounded by braces <code class="docutils literal"><span class="pre">{}</span></code>. The fields are replaced with formatted
|
||||
arguments in the resulting string.</p>
|
||||
<p><em>args</em> is an argument list representing arbitrary arguments.</p>
|
||||
<p>The <a class="reference external" href="https://github.com/fmtlib/fmt/blob/master/README.rst#speed-tests">performance of the format API</a> is close
|
||||
to that of glibc’s <code class="docutils literal"><span class="pre">printf</span></code> and better than the performance of IOStreams.
|
||||
For even better speed use the <a class="reference internal" href="#write-api">write API</a>.</p>
|
||||
<span class="target" id="format"></span><dl class="function">
|
||||
<dt id="_CPPv2N3fmt6formatE10CStringRef7ArgList">
|
||||
<span id="fmt::format__CStringRef.ArgList"></span><span class="target" id="formatformat_8h_1a638f25c535b3bfa12dc1478b11885b6f"></span>std::string <code class="descclassname">fmt::</code><code class="descname">format</code><span class="sig-paren">(</span>CStringRef <em>format_str</em>, <a class="reference internal" href="#_CPPv2N3fmt7ArgListE" title="fmt::ArgList">ArgList</a> <em>args</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt6formatE10CStringRef7ArgList" title="Permalink to this definition">¶</a></dt>
|
||||
@@ -140,18 +153,10 @@ arguments in the resulting string.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt8literalsli7_formatEPKcNSt6size_tE">
|
||||
<span class="target" id="formatformat_8h_1a8f568cdac4d075838347616fc4899417"></span>internal::UdlFormat<char> <code class="descclassname">fmt::literals::</code><code class="descname">operator""_format</code><span class="sig-paren">(</span><em class="property">const</em> char *<em>s</em>, std::size_t<span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt8literalsli7_formatEPKcNSt6size_tE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>C++11 literal equivalent of <a class="reference internal" href="#_CPPv2N3fmt6formatE10CStringRef7ArgList" title="fmt::format"><code class="xref cpp cpp-func docutils literal"><span class="pre">fmt::format()</span></code></a>.</p>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">using</span> <span class="k">namespace</span> <span class="n">fmt</span><span class="o">::</span><span class="n">literals</span><span class="p">;</span>
|
||||
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">message</span> <span class="o">=</span> <span class="s">"The answer is {}"</span><span class="n">_format</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span>
|
||||
</pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="first admonition-title">Warning</p>
|
||||
<p class="last">doxygenfunction: Cannot find function “operator”“_format” in doxygen xml output for project “format” from directory: /home/foonathan/Programming/fmt/build/doc/doxyxml</p>
|
||||
</div>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<span class="target" id="print"></span><dl class="function">
|
||||
<dt id="_CPPv2N3fmt5printE10CStringRef7ArgList">
|
||||
<span id="fmt::print__CStringRef.ArgList"></span><span class="target" id="formatformat_8h_1a7cfad68e64995774f11072aaf5008e8a"></span>void <code class="descclassname">fmt::</code><code class="descname">print</code><span class="sig-paren">(</span>CStringRef <em>format_str</em>, <a class="reference internal" href="#_CPPv2N3fmt7ArgListE" title="fmt::ArgList">ArgList</a> <em>args</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt5printE10CStringRef7ArgList" title="Permalink to this definition">¶</a></dt>
|
||||
@@ -180,7 +185,8 @@ arguments in the resulting string.</p>
|
||||
<dt id="_CPPv2N3fmt14BasicFormatterE">
|
||||
<span id="fmt::BasicFormatter"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">BasicFormatter</code><a class="headerlink" href="#_CPPv2N3fmt14BasicFormatterE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>This template formats data and writes the output to a writer. </p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<p>Inherits from fmt::internal::FormatterBase</p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Types</p>
|
||||
<dl class="type">
|
||||
<dt id="_CPPv2N3fmt14BasicFormatter4CharE">
|
||||
@@ -189,7 +195,7 @@ arguments in the resulting string.</p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
<div class="breathe-sectiondef container">
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt14BasicFormatter14BasicFormatterERK7ArgListR11BasicWriterI4CharE">
|
||||
@@ -217,8 +223,8 @@ appropriate lifetimes.</p>
|
||||
|
||||
<div class="section" id="date-and-time-formatting">
|
||||
<h3>Date and time formatting<a class="headerlink" href="#date-and-time-formatting" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The library supports <a class="reference external" href="http://en.cppreference.com/w/cpp/chrono/c/strftime">strftime</a>-like
|
||||
date and time formatting:</p>
|
||||
<p>The library supports <a class="reference external" href="http://en.cppreference.com/w/cpp/chrono/c/strftime">strftime</a>-like date and time
|
||||
formatting:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">"fmt/time.h"</span><span class="cp"></span>
|
||||
|
||||
<span class="n">std</span><span class="o">::</span><span class="kt">time_t</span> <span class="n">t</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">time</span><span class="p">(</span><span class="k">nullptr</span><span class="p">);</span>
|
||||
@@ -229,6 +235,32 @@ date and time formatting:</p>
|
||||
<p>The format string syntax is described in the documentation of
|
||||
<a class="reference external" href="http://en.cppreference.com/w/cpp/chrono/c/strftime">strftime</a>.</p>
|
||||
</div>
|
||||
<div class="section" id="formatting-user-defined-types">
|
||||
<h3>Formatting user-defined types<a class="headerlink" href="#formatting-user-defined-types" title="Permalink to this headline">¶</a></h3>
|
||||
<p>A custom <code class="docutils literal"><span class="pre">format_arg</span></code> function may be implemented and used to format any
|
||||
user-defined type. That is how date and time formatting described in the
|
||||
previous section is implemented in <code class="file docutils literal"><span class="pre">fmt/time.h</span></code>. The following example
|
||||
shows how to implement custom formatting for a user-defined structure.</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">MyStruct</span> <span class="p">{</span> <span class="kt">double</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">;</span> <span class="p">};</span>
|
||||
|
||||
<span class="kt">void</span> <span class="nf">format_arg</span><span class="p">(</span><span class="n">fmt</span><span class="o">::</span><span class="n">BasicFormatter</span><span class="o"><</span><span class="kt">char</span><span class="o">></span> <span class="o">&</span><span class="n">f</span><span class="p">,</span>
|
||||
<span class="k">const</span> <span class="kt">char</span> <span class="o">*&</span><span class="n">format_str</span><span class="p">,</span> <span class="k">const</span> <span class="n">MyStruct</span> <span class="o">&</span><span class="n">s</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="n">f</span><span class="p">.</span><span class="n">writer</span><span class="p">().</span><span class="n">write</span><span class="p">(</span><span class="s">"[MyStruct: a={:.1f}, b={:.2f}]"</span><span class="p">,</span> <span class="n">s</span><span class="p">.</span><span class="n">a</span><span class="p">,</span> <span class="n">s</span><span class="p">.</span><span class="n">b</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="n">MyStruct</span> <span class="n">m</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span> <span class="p">};</span>
|
||||
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">s</span> <span class="o">=</span> <span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">"m={}"</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>
|
||||
<span class="c1">// s == "m=[MyStruct: a=1.0, b=2.00]"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Note in the example above the <code class="docutils literal"><span class="pre">format_arg</span></code> function ignores the contents of
|
||||
<code class="docutils literal"><span class="pre">format_str</span></code> so the type will always be formatted as specified. See
|
||||
<code class="docutils literal"><span class="pre">format_arg</span></code> in <code class="file docutils literal"><span class="pre">fmt/time.h</span></code> for an advanced example of how to use
|
||||
the <code class="docutils literal"><span class="pre">format_str</span></code> argument to customize the formatted output.</p>
|
||||
<p>This section shows how to define a custom format function for a user-defined
|
||||
type. The next section describes how to get <code class="docutils literal"><span class="pre">fmt</span></code> to use a conventional stream
|
||||
output <code class="docutils literal"><span class="pre">operator<<</span></code> when one is defined for a user-defined type.</p>
|
||||
</div>
|
||||
<div class="section" id="std-ostream-support">
|
||||
<h3><code class="docutils literal"><span class="pre">std::ostream</span></code> support<a class="headerlink" href="#std-ostream-support" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The header <code class="docutils literal"><span class="pre">fmt/ostream.h</span></code> provides <code class="docutils literal"><span class="pre">std::ostream</span></code> support including
|
||||
@@ -238,7 +270,7 @@ formatting of user-defined types that have overloaded <code class="docutils lite
|
||||
<span class="k">class</span> <span class="nc">Date</span> <span class="p">{</span>
|
||||
<span class="kt">int</span> <span class="n">year_</span><span class="p">,</span> <span class="n">month_</span><span class="p">,</span> <span class="n">day_</span><span class="p">;</span>
|
||||
<span class="k">public</span><span class="o">:</span>
|
||||
<span class="n">Date</span><span class="p">(</span><span class="kt">int</span> <span class="n">year</span><span class="p">,</span> <span class="kt">int</span> <span class="n">month</span><span class="p">,</span> <span class="kt">int</span> <span class="n">day</span><span class="p">)</span> <span class="o">:</span> <span class="n">year_</span><span class="p">(</span><span class="n">year</span><span class="p">),</span> <span class="n">month_</span><span class="p">(</span><span class="n">month</span><span class="p">),</span> <span class="n">day_</span><span class="p">(</span><span class="n">day</span><span class="p">)</span> <span class="p">{}</span>
|
||||
<span class="n">Date</span><span class="p">(</span><span class="kt">int</span> <span class="n">year</span><span class="p">,</span> <span class="kt">int</span> <span class="n">month</span><span class="p">,</span> <span class="kt">int</span> <span class="n">day</span><span class="p">)</span><span class="o">:</span> <span class="n">year_</span><span class="p">(</span><span class="n">year</span><span class="p">),</span> <span class="n">month_</span><span class="p">(</span><span class="n">month</span><span class="p">),</span> <span class="n">day_</span><span class="p">(</span><span class="n">day</span><span class="p">)</span> <span class="p">{}</span>
|
||||
|
||||
<span class="k">friend</span> <span class="n">std</span><span class="o">::</span><span class="n">ostream</span> <span class="o">&</span><span class="k">operator</span><span class="o"><<</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">ostream</span> <span class="o">&</span><span class="n">os</span><span class="p">,</span> <span class="k">const</span> <span class="n">Date</span> <span class="o">&</span><span class="n">d</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="k">return</span> <span class="n">os</span> <span class="o"><<</span> <span class="n">d</span><span class="p">.</span><span class="n">year_</span> <span class="o"><<</span> <span class="sc">'-'</span> <span class="o"><<</span> <span class="n">d</span><span class="p">.</span><span class="n">month_</span> <span class="o"><<</span> <span class="sc">'-'</span> <span class="o"><<</span> <span class="n">d</span><span class="p">.</span><span class="n">day_</span><span class="p">;</span>
|
||||
@@ -260,17 +292,6 @@ formatting of user-defined types that have overloaded <code class="docutils lite
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt7fprintfERNSt7ostreamE10CStringRef7ArgList">
|
||||
<span id="fmt::fprintf__osR.CStringRef.ArgList"></span><span class="target" id="formatostream_8h_1adf9e00e4ddf5cad224a101333cfac9e8"></span>int <code class="descclassname">fmt::</code><code class="descname">fprintf</code><span class="sig-paren">(</span>std::ostream &<em>os</em>, CStringRef <em>format_str</em>, <a class="reference internal" href="#_CPPv2N3fmt7ArgListE" title="fmt::ArgList">ArgList</a> <em>args</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt7fprintfERNSt7ostreamE10CStringRef7ArgList" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Prints formatted data to the stream <em>os</em>.</p>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fprintf</span><span class="p">(</span><span class="n">cerr</span><span class="p">,</span> <span class="s">"Don't %s!"</span><span class="p">,</span> <span class="s">"panic"</span><span class="p">);</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
<div class="section" id="argument-formatters">
|
||||
<h3>Argument formatters<a class="headerlink" href="#argument-formatters" title="Permalink to this headline">¶</a></h3>
|
||||
@@ -279,7 +300,7 @@ custom argument formatter class:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="c1">// A custom argument formatter that formats negative integers as unsigned</span>
|
||||
<span class="c1">// with the ``x`` format specifier.</span>
|
||||
<span class="k">class</span> <span class="nc">CustomArgFormatter</span> <span class="o">:</span>
|
||||
<span class="k">public</span> <span class="n">fmt</span><span class="o">::</span><span class="n">BasicArgFormatter</span><span class="o"><</span><span class="n">CustomArgFormatter</span><span class="p">,</span> <span class="kt">char</span><span class="o">></span> <span class="p">{</span>
|
||||
<span class="k">public</span> <span class="n">fmt</span><span class="o">::</span><span class="n">BasicArgFormatter</span><span class="o"><</span><span class="n">CustomArgFormatter</span><span class="p">,</span> <span class="kt">char</span><span class="o">></span> <span class="p">{</span>
|
||||
<span class="k">public</span><span class="o">:</span>
|
||||
<span class="n">CustomArgFormatter</span><span class="p">(</span><span class="n">fmt</span><span class="o">::</span><span class="n">BasicFormatter</span><span class="o"><</span><span class="kt">char</span><span class="p">,</span> <span class="n">CustomArgFormatter</span><span class="o">></span> <span class="o">&</span><span class="n">f</span><span class="p">,</span>
|
||||
<span class="n">fmt</span><span class="o">::</span><span class="n">FormatSpec</span> <span class="o">&</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">fmt</span><span class="p">)</span>
|
||||
@@ -329,7 +350,7 @@ then a corresponding method of <a class="reference internal" href="#_CPPv2N3fmt1
|
||||
</pre></div>
|
||||
</div>
|
||||
</p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt10ArgVisitor9visit_intEi">
|
||||
@@ -440,7 +461,7 @@ called.</p>
|
||||
|
||||
<dl class="class">
|
||||
<dt>
|
||||
<span class="target" id="formatclassfmt_1_1_basic_arg_formatter"></span><em class="property">template </em><typename <em>Impl</em>, typename <em>Char</em>></dt>
|
||||
<span class="target" id="formatclassfmt_1_1_basic_arg_formatter"></span><em class="property">template </em><typename <em>Impl</em>, typename <em>Char</em>, typename <em>Spec</em> = fmt::FormatSpec></dt>
|
||||
<dt id="_CPPv2N3fmt17BasicArgFormatterE">
|
||||
<span id="fmt::BasicArgFormatter"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">BasicArgFormatter</code><a class="headerlink" href="#_CPPv2N3fmt17BasicArgFormatterE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>An argument formatter based on the <a class="reference external" href="http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern">curiously recurring template pattern</a>.</p>
|
||||
@@ -455,11 +476,12 @@ will be called. If the subclass doesn’t contain a method with this signatu
|
||||
then a corresponding method of <a class="reference internal" href="#_CPPv2N3fmt17BasicArgFormatterE" title="fmt::BasicArgFormatter"><code class="xref cpp cpp-any docutils literal"><span class="pre">BasicArgFormatter</span></code></a> or its superclass
|
||||
will be called.</p>
|
||||
</p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<p>Inherits from fmt::internal::ArgFormatterBase< Impl, Char, Spec ></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt17BasicArgFormatter17BasicArgFormatterER14BasicFormatterI4Char4ImplER10FormatSpecPK4Char">
|
||||
<span id="fmt::BasicArgFormatter::BasicArgFormatter__BasicFormatter:Char.Impl:R.FormatSpecR.CharCP"></span><span class="target" id="formatclassfmt_1_1_basic_arg_formatter_1a207b17b258c5e16cf61ebfc9b13211d3"></span><code class="descname">BasicArgFormatter</code><span class="sig-paren">(</span><a class="reference internal" href="#_CPPv2N3fmt14BasicFormatterE" title="fmt::BasicFormatter">BasicFormatter</a><Char, Impl> &<em>formatter</em>, FormatSpec &<em>spec</em>, <em class="property">const</em> Char *<em>fmt</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt17BasicArgFormatter17BasicArgFormatterER14BasicFormatterI4Char4ImplER10FormatSpecPK4Char" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2N3fmt17BasicArgFormatter17BasicArgFormatterER14BasicFormatterI4Char4ImplER4SpecPK4Char">
|
||||
<span id="fmt::BasicArgFormatter::BasicArgFormatter__BasicFormatter:Char.Impl:R.SpecR.CharCP"></span><span class="target" id="formatclassfmt_1_1_basic_arg_formatter_1a9fbfaaf573b6714ed03894326b0a5106"></span><code class="descname">BasicArgFormatter</code><span class="sig-paren">(</span><a class="reference internal" href="#_CPPv2N3fmt14BasicFormatterE" title="fmt::BasicFormatter">BasicFormatter</a><Char, Impl> &<em>formatter</em>, Spec &<em>spec</em>, <em class="property">const</em> Char *<em>fmt</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt17BasicArgFormatter17BasicArgFormatterER14BasicFormatterI4Char4ImplER4SpecPK4Char" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Constructs an argument formatter object.
|
||||
<em>formatter</em> is a reference to the main formatter object, <em>spec</em> contains
|
||||
format specifier information for standard argument types, and <em>fmt</em> points
|
||||
@@ -469,8 +491,8 @@ to the part of the format string being parsed for custom argument types.</p>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt17BasicArgFormatter12visit_customEN8internal3Arg11CustomValueE">
|
||||
<span id="fmt::BasicArgFormatter::visit_custom__internal::Arg::CustomValue"></span><span class="target" id="formatclassfmt_1_1_basic_arg_formatter_1ae0aab0f90c9c93e3513203fc84c2c4dc"></span>void <code class="descname">visit_custom</code><span class="sig-paren">(</span>internal::Arg::CustomValue <em>c</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt17BasicArgFormatter12visit_customEN8internal3Arg11CustomValueE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Formats argument of a custom (user-defined) type. </p>
|
||||
<span id="fmt::BasicArgFormatter::visit_custom__internal::Arg::CustomValue"></span><span class="target" id="formatclassfmt_1_1_basic_arg_formatter_1acc822e8efaa99b664deaf38b08950b88"></span>void <code class="descname">visit_custom</code><span class="sig-paren">(</span>internal::Arg::CustomValue <em>c</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt17BasicArgFormatter12visit_customEN8internal3Arg11CustomValueE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Formats an argument of a custom (user-defined) type. </p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
@@ -482,7 +504,8 @@ to the part of the format string being parsed for custom argument types.</p>
|
||||
<dt id="_CPPv2N3fmt12ArgFormatterE">
|
||||
<span id="fmt::ArgFormatter"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">ArgFormatter</code><a class="headerlink" href="#_CPPv2N3fmt12ArgFormatterE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>The default argument formatter. </p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<p>Inherits from <a class="reference internal" href="#formatclassfmt_1_1_basic_arg_formatter"><span class="std std-ref">fmt::BasicArgFormatter< ArgFormatter< Char >, Char, FormatSpec ></span></a></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt12ArgFormatter12ArgFormatterER14BasicFormatterI4CharER10FormatSpecPK4Char">
|
||||
@@ -494,13 +517,16 @@ to the part of the format string being parsed for custom argument types.</p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
<div class="section" id="printf-formatting-functions">
|
||||
<h3>Printf formatting functions<a class="headerlink" href="#printf-formatting-functions" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The following functions use <a class="reference external" href="http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html">printf format string syntax</a> with
|
||||
a POSIX extension for positional arguments.</p>
|
||||
<div class="section" id="printf-formatting">
|
||||
<h3>Printf formatting<a class="headerlink" href="#printf-formatting" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The header <code class="docutils literal"><span class="pre">fmt/printf.h</span></code> provides <code class="docutils literal"><span class="pre">printf</span></code>-like formatting functionality.
|
||||
The following functions use <a class="reference external" href="http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html">printf format string syntax</a> with
|
||||
the POSIX extension for positional arguments. Unlike their standard
|
||||
counterparts, the <code class="docutils literal"><span class="pre">fmt</span></code> functions are type-safe and throw an exception if an
|
||||
argument type doesn’t match its format specification.</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt6printfE10CStringRef7ArgList">
|
||||
<span id="fmt::printf__CStringRef.ArgList"></span><span class="target" id="formatformat_8h_1aa936ffccf89f4609cd9fce18825f0b14"></span>int <code class="descclassname">fmt::</code><code class="descname">printf</code><span class="sig-paren">(</span>CStringRef <em>format</em>, <a class="reference internal" href="#_CPPv2N3fmt7ArgListE" title="fmt::ArgList">ArgList</a> <em>args</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt6printfE10CStringRef7ArgList" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::printf__CStringRef.ArgList"></span><span class="target" id="formatprintf_8h_1aa936ffccf89f4609cd9fce18825f0b14"></span>int <code class="descclassname">fmt::</code><code class="descname">printf</code><span class="sig-paren">(</span>CStringRef <em>format</em>, <a class="reference internal" href="#_CPPv2N3fmt7ArgListE" title="fmt::ArgList">ArgList</a> <em>args</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt6printfE10CStringRef7ArgList" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Prints formatted data to <code class="docutils literal"><span class="pre">stdout</span></code>.</p>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">printf</span><span class="p">(</span><span class="s">"Elapsed time: %.2f seconds"</span><span class="p">,</span> <span class="mf">1.23</span><span class="p">);</span>
|
||||
@@ -511,7 +537,7 @@ a POSIX extension for positional arguments.</p>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt7fprintfEPNSt4FILEE10CStringRef7ArgList">
|
||||
<span id="fmt::fprintf__std::FILEP.CStringRef.ArgList"></span><span class="target" id="formatformat_8h_1ae70c0a9615eef5e1e78450496d2a90e6"></span>int <code class="descclassname">fmt::</code><code class="descname">fprintf</code><span class="sig-paren">(</span>std::FILE *<em>f</em>, CStringRef <em>format</em>, <a class="reference internal" href="#_CPPv2N3fmt7ArgListE" title="fmt::ArgList">ArgList</a> <em>args</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt7fprintfEPNSt4FILEE10CStringRef7ArgList" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::fprintf__std::FILEP.CStringRef.ArgList"></span><span class="target" id="formatprintf_8h_1ae70c0a9615eef5e1e78450496d2a90e6"></span>int <code class="descclassname">fmt::</code><code class="descname">fprintf</code><span class="sig-paren">(</span>std::FILE *<em>f</em>, CStringRef <em>format</em>, <a class="reference internal" href="#_CPPv2N3fmt7ArgListE" title="fmt::ArgList">ArgList</a> <em>args</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt7fprintfEPNSt4FILEE10CStringRef7ArgList" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Prints formatted data to the file <em>f</em>.</p>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Don't %s!"</span><span class="p">,</span> <span class="s">"panic"</span><span class="p">);</span>
|
||||
@@ -520,9 +546,20 @@ a POSIX extension for positional arguments.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt7fprintfERNSt7ostreamE10CStringRef7ArgList">
|
||||
<span id="fmt::fprintf__osR.CStringRef.ArgList"></span><span class="target" id="formatprintf_8h_1adf9e00e4ddf5cad224a101333cfac9e8"></span>int <code class="descclassname">fmt::</code><code class="descname">fprintf</code><span class="sig-paren">(</span>std::ostream &<em>os</em>, CStringRef <em>format_str</em>, <a class="reference internal" href="#_CPPv2N3fmt7ArgListE" title="fmt::ArgList">ArgList</a> <em>args</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt7fprintfERNSt7ostreamE10CStringRef7ArgList" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Prints formatted data to the stream <em>os</em>.</p>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fprintf</span><span class="p">(</span><span class="n">cerr</span><span class="p">,</span> <span class="s">"Don't %s!"</span><span class="p">,</span> <span class="s">"panic"</span><span class="p">);</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt7sprintfE10CStringRef7ArgList">
|
||||
<span id="fmt::sprintf__CStringRef.ArgList"></span><span class="target" id="formatformat_8h_1a956d655d1291fb85203c58fadd4bba1a"></span>std::string <code class="descclassname">fmt::</code><code class="descname">sprintf</code><span class="sig-paren">(</span>CStringRef <em>format</em>, <a class="reference internal" href="#_CPPv2N3fmt7ArgListE" title="fmt::ArgList">ArgList</a> <em>args</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt7sprintfE10CStringRef7ArgList" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::sprintf__CStringRef.ArgList"></span><span class="target" id="formatprintf_8h_1a956d655d1291fb85203c58fadd4bba1a"></span>std::string <code class="descclassname">fmt::</code><code class="descname">sprintf</code><span class="sig-paren">(</span>CStringRef <em>format</em>, <a class="reference internal" href="#_CPPv2N3fmt7ArgListE" title="fmt::ArgList">ArgList</a> <em>args</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt7sprintfE10CStringRef7ArgList" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Formats arguments and returns the result as a string.</p>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">message</span> <span class="o">=</span> <span class="n">fmt</span><span class="o">::</span><span class="n">sprintf</span><span class="p">(</span><span class="s">"The answer is %d"</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span>
|
||||
@@ -531,10 +568,124 @@ a POSIX extension for positional arguments.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="class">
|
||||
<dt>
|
||||
<span class="target" id="formatclassfmt_1_1_printf_formatter"></span><em class="property">template </em><typename <em>Char</em>, typename <em>ArgFormatter</em> = <a class="reference internal" href="#formatclassfmt_1_1_printf_arg_formatter"><span class="std std-ref">PrintfArgFormatter</span></a><Char>></dt>
|
||||
<dt id="_CPPv2N3fmt15PrintfFormatterE">
|
||||
<span id="fmt::PrintfFormatter"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">PrintfFormatter</code><a class="headerlink" href="#_CPPv2N3fmt15PrintfFormatterE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>This template formats data and writes the output to a writer. </p>
|
||||
<p>Inherits from fmt::internal::FormatterBase</p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt15PrintfFormatter15PrintfFormatterERK7ArgListR11BasicWriterI4CharE">
|
||||
<span id="fmt::PrintfFormatter::PrintfFormatter__ArgListCR.BasicWriter:Char:R"></span><span class="target" id="formatclassfmt_1_1_printf_formatter_1a9cb3cad9a8e4cd08445e9ff2338d40b0"></span><code class="descname">PrintfFormatter</code><span class="sig-paren">(</span><em class="property">const</em> <a class="reference internal" href="#_CPPv2N3fmt7ArgListE" title="fmt::ArgList">ArgList</a> &<em>al</em>, <a class="reference internal" href="#_CPPv2N3fmt11BasicWriterE" title="fmt::BasicWriter">BasicWriter</a><Char> &<em>w</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt15PrintfFormatter15PrintfFormatterERK7ArgListR11BasicWriterI4CharE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Constructs a <code class="docutils literal"><span class="pre">PrintfFormatter</span></code> object. References to the arguments and
|
||||
the writer are stored in the formatter object so make sure they have
|
||||
appropriate lifetimes.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt15PrintfFormatter6formatE15BasicCStringRefI4CharE">
|
||||
<span id="fmt::PrintfFormatter::format__BasicCStringRef:Char:"></span><span class="target" id="formatclassfmt_1_1_printf_formatter_1a295c50e11b9a77720c8078f287040e5c"></span>void <code class="descname">format</code><span class="sig-paren">(</span><a class="reference internal" href="#_CPPv2N3fmt15BasicCStringRefE" title="fmt::BasicCStringRef">BasicCStringRef</a><Char> <em>format_str</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt15PrintfFormatter6formatE15BasicCStringRefI4CharE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Formats stored arguments and writes the output to the writer. </p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="class">
|
||||
<dt>
|
||||
<span class="target" id="formatclassfmt_1_1_basic_printf_arg_formatter"></span><em class="property">template </em><typename <em>Impl</em>, typename <em>Char</em>, typename <em>Spec</em>></dt>
|
||||
<dt id="_CPPv2N3fmt23BasicPrintfArgFormatterE">
|
||||
<span id="fmt::BasicPrintfArgFormatter"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">BasicPrintfArgFormatter</code><a class="headerlink" href="#_CPPv2N3fmt23BasicPrintfArgFormatterE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>A <code class="docutils literal"><span class="pre">printf</span></code> argument formatter based on the <a class="reference external" href="http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern">curiously recurring template
|
||||
pattern</a>.</p>
|
||||
<p>To use <a class="reference internal" href="#_CPPv2N3fmt23BasicPrintfArgFormatterE" title="fmt::BasicPrintfArgFormatter"><code class="xref cpp cpp-any docutils literal"><span class="pre">BasicPrintfArgFormatter</span></code></a> define a subclass that implements some
|
||||
or all of the visit methods with the same signatures as the methods in
|
||||
<a class="reference internal" href="#_CPPv2N3fmt10ArgVisitorE" title="fmt::ArgVisitor"><code class="xref cpp cpp-any docutils literal"><span class="pre">ArgVisitor</span></code></a>, for example, <a class="reference internal" href="#_CPPv2N3fmt10ArgVisitor9visit_intEi" title="fmt::ArgVisitor::visit_int"><code class="xref cpp cpp-any docutils literal"><span class="pre">visit_int()</span></code></a>.
|
||||
Pass the subclass as the <em>Impl</em> template parameter. When a formatting
|
||||
function processes an argument, it will dispatch to a visit method
|
||||
specific to the argument type. For example, if the argument type is
|
||||
<code class="docutils literal"><span class="pre">double</span></code> then the <a class="reference internal" href="#_CPPv2N3fmt10ArgVisitor12visit_doubleEd" title="fmt::ArgVisitor::visit_double"><code class="xref cpp cpp-any docutils literal"><span class="pre">visit_double()</span></code></a> method of a subclass
|
||||
will be called. If the subclass doesn’t contain a method with this signature,
|
||||
then a corresponding method of <a class="reference internal" href="#_CPPv2N3fmt23BasicPrintfArgFormatterE" title="fmt::BasicPrintfArgFormatter"><code class="xref cpp cpp-any docutils literal"><span class="pre">BasicPrintfArgFormatter</span></code></a> or its
|
||||
superclass will be called.</p>
|
||||
</p>
|
||||
<p>Inherits from fmt::internal::ArgFormatterBase< Impl, Char, Spec ></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt23BasicPrintfArgFormatter23BasicPrintfArgFormatterER11BasicWriterI4CharER4Spec">
|
||||
<span id="fmt::BasicPrintfArgFormatter::BasicPrintfArgFormatter__BasicWriter:Char:R.SpecR"></span><span class="target" id="formatclassfmt_1_1_basic_printf_arg_formatter_1a7027cf03f0a54f8d7e53563e948d9f54"></span><code class="descname">BasicPrintfArgFormatter</code><span class="sig-paren">(</span><a class="reference internal" href="#_CPPv2N3fmt11BasicWriterE" title="fmt::BasicWriter">BasicWriter</a><Char> &<em>w</em>, Spec &<em>s</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt23BasicPrintfArgFormatter23BasicPrintfArgFormatterER11BasicWriterI4CharER4Spec" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Constructs an argument formatter object.
|
||||
<em>writer</em> is a reference to the output writer and <em>spec</em> contains format
|
||||
specifier information for standard argument types.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt23BasicPrintfArgFormatter10visit_boolEb">
|
||||
<span id="fmt::BasicPrintfArgFormatter::visit_bool__b"></span><span class="target" id="formatclassfmt_1_1_basic_printf_arg_formatter_1a5a8896e3b7e60b678ad7ac1145d2d7db"></span>void <code class="descname">visit_bool</code><span class="sig-paren">(</span>bool <em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt23BasicPrintfArgFormatter10visit_boolEb" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Formats an argument of type <code class="docutils literal"><span class="pre">bool</span></code>. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt23BasicPrintfArgFormatter10visit_charEi">
|
||||
<span id="fmt::BasicPrintfArgFormatter::visit_char__i"></span><span class="target" id="formatclassfmt_1_1_basic_printf_arg_formatter_1a6d6a9710fe756a8682efa6e83eea8146"></span>void <code class="descname">visit_char</code><span class="sig-paren">(</span>int <em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt23BasicPrintfArgFormatter10visit_charEi" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Formats a character. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt23BasicPrintfArgFormatter13visit_cstringEPKc">
|
||||
<span id="fmt::BasicPrintfArgFormatter::visit_cstring__cCP"></span><span class="target" id="formatclassfmt_1_1_basic_printf_arg_formatter_1a202e5093c8d7ab388c05f58956e8f721"></span>void <code class="descname">visit_cstring</code><span class="sig-paren">(</span><em class="property">const</em> char *<em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt23BasicPrintfArgFormatter13visit_cstringEPKc" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Formats a null-terminated C string. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt23BasicPrintfArgFormatter13visit_pointerEPKv">
|
||||
<span id="fmt::BasicPrintfArgFormatter::visit_pointer__voidCP"></span><span class="target" id="formatclassfmt_1_1_basic_printf_arg_formatter_1a4184ac39a994f38d4b4850393e413a1c"></span>void <code class="descname">visit_pointer</code><span class="sig-paren">(</span><em class="property">const</em> void *<em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt23BasicPrintfArgFormatter13visit_pointerEPKv" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Formats a pointer. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt23BasicPrintfArgFormatter12visit_customEN8internal3Arg11CustomValueE">
|
||||
<span id="fmt::BasicPrintfArgFormatter::visit_custom__internal::Arg::CustomValue"></span><span class="target" id="formatclassfmt_1_1_basic_printf_arg_formatter_1a5ad1e99dfd69b88a6b7940c1bfc52d23"></span>void <code class="descname">visit_custom</code><span class="sig-paren">(</span>internal::Arg::CustomValue <em>c</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt23BasicPrintfArgFormatter12visit_customEN8internal3Arg11CustomValueE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Formats an argument of a custom (user-defined) type. </p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="class">
|
||||
<dt>
|
||||
<span class="target" id="formatclassfmt_1_1_printf_arg_formatter"></span><em class="property">template </em><<em class="property">typename</em> Char></dt>
|
||||
<dt id="_CPPv2N3fmt18PrintfArgFormatterE">
|
||||
<span id="fmt::PrintfArgFormatter"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">PrintfArgFormatter</code><a class="headerlink" href="#_CPPv2N3fmt18PrintfArgFormatterE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>The default printf argument formatter. </p>
|
||||
<p>Inherits from <a class="reference internal" href="#formatclassfmt_1_1_basic_printf_arg_formatter"><span class="std std-ref">fmt::BasicPrintfArgFormatter< PrintfArgFormatter< Char >, Char, FormatSpec ></span></a></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt18PrintfArgFormatter18PrintfArgFormatterER11BasicWriterI4CharER10FormatSpec">
|
||||
<span id="fmt::PrintfArgFormatter::PrintfArgFormatter__BasicWriter:Char:R.FormatSpecR"></span><span class="target" id="formatclassfmt_1_1_printf_arg_formatter_1aa4b9526d3c614205d607f63918c33245"></span><code class="descname">PrintfArgFormatter</code><span class="sig-paren">(</span><a class="reference internal" href="#_CPPv2N3fmt11BasicWriterE" title="fmt::BasicWriter">BasicWriter</a><Char> &<em>w</em>, FormatSpec &<em>s</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt18PrintfArgFormatter18PrintfArgFormatterER11BasicWriterI4CharER10FormatSpec" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Constructs an argument formatter object. </p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="write-api">
|
||||
<h2>Write API<a class="headerlink" href="#write-api" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The write API provides classes for writing formatted data into character
|
||||
streams. It is usually faster than the <a class="reference internal" href="#format-api">format API</a> but, as IOStreams,
|
||||
may result in larger compiled code size. The main writer class is
|
||||
<a class="reference internal" href="#_CPPv2N3fmt17BasicMemoryWriterE" title="fmt::BasicMemoryWriter"><code class="xref cpp cpp-any docutils literal"><span class="pre">BasicMemoryWriter</span></code></a> which stores its output in a memory buffer and
|
||||
provides direct access to it. It is possible to create custom writers that
|
||||
store output elsewhere by subclassing <a class="reference internal" href="#_CPPv2N3fmt11BasicWriterE" title="fmt::BasicWriter"><code class="xref cpp cpp-any docutils literal"><span class="pre">BasicWriter</span></code></a>.</p>
|
||||
<dl class="class">
|
||||
<dt>
|
||||
<span class="target" id="formatclassfmt_1_1_basic_writer"></span><em class="property">template </em><typename <em>Char</em>></dt>
|
||||
@@ -564,37 +715,38 @@ such as <a class="reference internal" href="#_CPPv2N3fmt17BasicMemoryWriterE" ti
|
||||
</tbody>
|
||||
</table>
|
||||
</p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<p>Subclassed by <a class="reference internal" href="#formatclassfmt_1_1_basic_array_writer"><span class="std std-ref">fmt::BasicArrayWriter< Char ></span></a>, <a class="reference internal" href="#formatclassfmt_1_1_basic_memory_writer"><span class="std std-ref">fmt::BasicMemoryWriter< Char, Allocator ></span></a>, <a class="reference internal" href="#formatclassfmt_1_1_basic_string_writer"><span class="std std-ref">fmt::BasicStringWriter< Char, Allocator ></span></a></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt11BasicWriterD0Ev">
|
||||
<span id="fmt::BasicWriter::~BasicWriter"></span>virtual <span class="target" id="formatclassfmt_1_1_basic_writer_1a25f6fc2e43d3bcfb3de9ac33afe6050d"></span><code class="descname">~BasicWriter</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt11BasicWriterD0Ev" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::BasicWriter::~BasicWriter"></span><span class="target" id="formatclassfmt_1_1_basic_writer_1a25f6fc2e43d3bcfb3de9ac33afe6050d"></span><em class="property">virtual</em> <code class="descname">~BasicWriter</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt11BasicWriterD0Ev" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Destroys a <code class="docutils literal"><span class="pre">BasicWriter</span></code> object.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt11BasicWriter4sizeEv">
|
||||
<span id="fmt::BasicWriter::size"></span><span class="target" id="formatclassfmt_1_1_basic_writer_1a1b6721b4ba4d3fa18ac781a36616cc2a"></span>std::size_t <code class="descname">size</code><span class="sig-paren">(</span><span class="sig-paren">)</span> const<a class="headerlink" href="#_CPPv2N3fmt11BasicWriter4sizeEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2NK3fmt11BasicWriter4sizeEv">
|
||||
<span id="fmt::BasicWriter::sizeC"></span><span class="target" id="formatclassfmt_1_1_basic_writer_1a8d4534eea273ef4a3dd9078b995d3d15"></span>std::size_t <code class="descname">size</code><span class="sig-paren">(</span><span class="sig-paren">)</span> <em class="property">const</em><a class="headerlink" href="#_CPPv2NK3fmt11BasicWriter4sizeEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns the total number of characters written. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt11BasicWriter4dataEv">
|
||||
<span id="fmt::BasicWriter::data"></span><span class="target" id="formatclassfmt_1_1_basic_writer_1a6f3f431fab4a937cd6844a5bda609391"></span><em class="property">const</em> Char *<code class="descname">data</code><span class="sig-paren">(</span><span class="sig-paren">)</span> const<a class="headerlink" href="#_CPPv2N3fmt11BasicWriter4dataEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2NK3fmt11BasicWriter4dataEv">
|
||||
<span id="fmt::BasicWriter::dataC"></span><span class="target" id="formatclassfmt_1_1_basic_writer_1a06ada257ca9ae580212d6fe0147fe2cc"></span><em class="property">const</em> Char *<code class="descname">data</code><span class="sig-paren">(</span><span class="sig-paren">)</span> <em class="property">const</em><a class="headerlink" href="#_CPPv2NK3fmt11BasicWriter4dataEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns a pointer to the output buffer content. </p>
|
||||
<p>No terminating null character is appended. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt11BasicWriter5c_strEv">
|
||||
<span id="fmt::BasicWriter::c_str"></span><span class="target" id="formatclassfmt_1_1_basic_writer_1a8b68001f5c1c0ea851ddaef27dcbc691"></span><em class="property">const</em> Char *<code class="descname">c_str</code><span class="sig-paren">(</span><span class="sig-paren">)</span> const<a class="headerlink" href="#_CPPv2N3fmt11BasicWriter5c_strEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2NK3fmt11BasicWriter5c_strEv">
|
||||
<span id="fmt::BasicWriter::c_strC"></span><span class="target" id="formatclassfmt_1_1_basic_writer_1ab608044b16c838ed394cfe937e2ed8b9"></span><em class="property">const</em> Char *<code class="descname">c_str</code><span class="sig-paren">(</span><span class="sig-paren">)</span> <em class="property">const</em><a class="headerlink" href="#_CPPv2NK3fmt11BasicWriter5c_strEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns a pointer to the output buffer content with terminating null character appended. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt11BasicWriter3strEv">
|
||||
<span id="fmt::BasicWriter::str"></span><span class="target" id="formatclassfmt_1_1_basic_writer_1a91f06ced6e063ee77a99740e0e79faf6"></span>std::basic_string<Char> <code class="descname">str</code><span class="sig-paren">(</span><span class="sig-paren">)</span> const<a class="headerlink" href="#_CPPv2N3fmt11BasicWriter3strEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2NK3fmt11BasicWriter3strEv">
|
||||
<span id="fmt::BasicWriter::strC"></span><span class="target" id="formatclassfmt_1_1_basic_writer_1aac8dbeddff3d4e268d17a4f9c16264f6"></span>std::basic_string<Char> <code class="descname">str</code><span class="sig-paren">(</span><span class="sig-paren">)</span> <em class="property">const</em><a class="headerlink" href="#_CPPv2NK3fmt11BasicWriter3strEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Returns the content of the output buffer as an <code class="xref cpp cpp-any docutils literal"><span class="pre">std::string</span></code>.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
@@ -695,11 +847,12 @@ and the standard allocator:</p>
|
||||
<p>The output can be converted to an <code class="docutils literal"><span class="pre">std::string</span></code> with <code class="docutils literal"><span class="pre">out.str()</span></code> or
|
||||
accessed as a C string with <code class="docutils literal"><span class="pre">out.c_str()</span></code>.</p>
|
||||
</p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<p>Inherits from <a class="reference internal" href="#formatclassfmt_1_1_basic_writer"><span class="std std-ref">fmt::BasicWriter< Char ></span></a></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt17BasicMemoryWriter17BasicMemoryWriterERR17BasicMemoryWriter">
|
||||
<span id="fmt::BasicMemoryWriter::BasicMemoryWriter__BasicMemoryWriterRR"></span><span class="target" id="formatclassfmt_1_1_basic_memory_writer_1a245047763a93566d0a7c1f90e8901672"></span><code class="descname">BasicMemoryWriter</code><span class="sig-paren">(</span><a class="reference internal" href="#_CPPv2N3fmt17BasicMemoryWriterE" title="fmt::BasicMemoryWriter">BasicMemoryWriter</a> &&<em>other</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt17BasicMemoryWriter17BasicMemoryWriterERR17BasicMemoryWriter" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::BasicMemoryWriter::BasicMemoryWriter__BasicMemoryWriterRR"></span><span class="target" id="formatclassfmt_1_1_basic_memory_writer_1a245047763a93566d0a7c1f90e8901672"></span><code class="descname">BasicMemoryWriter</code><span class="sig-paren">(</span><a class="reference internal" href="#_CPPv2N3fmt17BasicMemoryWriter17BasicMemoryWriterERR17BasicMemoryWriter" title="fmt::BasicMemoryWriter::BasicMemoryWriter">BasicMemoryWriter</a> &&<em>other</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt17BasicMemoryWriter17BasicMemoryWriterERR17BasicMemoryWriter" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Constructs a <a class="reference internal" href="#_CPPv2N3fmt17BasicMemoryWriterE" title="fmt::BasicMemoryWriter"><code class="xref cpp cpp-class docutils literal"><span class="pre">fmt::BasicMemoryWriter</span></code></a> object moving the content
|
||||
of the other object to it.</p>
|
||||
</p>
|
||||
@@ -746,7 +899,8 @@ into the array.</p>
|
||||
</tbody>
|
||||
</table>
|
||||
</p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<p>Inherits from <a class="reference internal" href="#formatclassfmt_1_1_basic_writer"><span class="std std-ref">fmt::BasicWriter< Char ></span></a></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt16BasicArrayWriter16BasicArrayWriterEP4CharNSt6size_tE">
|
||||
@@ -769,27 +923,118 @@ size known at compile time.</p>
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="class">
|
||||
<dt>
|
||||
<span class="target" id="formatclassfmt_1_1_basic_string_writer"></span><em class="property">template </em><<em class="property">typename</em> Char, <em class="property">typename</em> Allocator = std::allocator<Char>></dt>
|
||||
<dt id="_CPPv2N3fmt17BasicStringWriterE">
|
||||
<span id="fmt::BasicStringWriter"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">BasicStringWriter</code><a class="headerlink" href="#_CPPv2N3fmt17BasicStringWriterE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>This class template provides operations for formatting and writing data
|
||||
into a character stream. The output is stored in a <code class="docutils literal"><span class="pre">std::basic_string</span></code>
|
||||
that grows dynamically.</p>
|
||||
<p>You can use one of the following typedefs for common character types
|
||||
and the standard allocator:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="35%" />
|
||||
<col width="65%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr class="row-odd"><th class="head">Type</th>
|
||||
<th class="head">Definition</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr class="row-even"><td>StringWriter</td>
|
||||
<td>BasicStringWriter<char></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>WStringWriter</td>
|
||||
<td>BasicStringWriter<wchar_t></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">StringWriter</span> <span class="n">out</span><span class="p">;</span>
|
||||
<span class="n">out</span> <span class="o"><<</span> <span class="s">"The answer is "</span> <span class="o"><<</span> <span class="mi">42</span> <span class="o"><<</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will write the following output to the <code class="docutils literal"><span class="pre">out</span></code> object:</p>
|
||||
<div class="highlight-none"><div class="highlight"><pre><span></span>The answer is 42
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The output can be moved to a <code class="docutils literal"><span class="pre">std::basic_string</span></code> with <code class="docutils literal"><span class="pre">out.move_to()</span></code>.</p>
|
||||
</p>
|
||||
<p>Inherits from <a class="reference internal" href="#formatclassfmt_1_1_basic_writer"><span class="std std-ref">fmt::BasicWriter< Char ></span></a></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt17BasicStringWriter17BasicStringWriterERK9Allocator">
|
||||
<span id="fmt::BasicStringWriter::BasicStringWriter__AllocatorCR"></span><span class="target" id="formatclassfmt_1_1_basic_string_writer_1a39e60f775feda49e58964a9c540831fc"></span><code class="descname">BasicStringWriter</code><span class="sig-paren">(</span><em class="property">const</em> Allocator &<em>allocator</em> = Allocator()<span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt17BasicStringWriter17BasicStringWriterERK9Allocator" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Constructs a <a class="reference internal" href="#_CPPv2N3fmt17BasicStringWriterE" title="fmt::BasicStringWriter"><code class="xref cpp cpp-class docutils literal"><span class="pre">fmt::BasicStringWriter</span></code></a> object.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt17BasicStringWriter7move_toERNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE">
|
||||
<span id="fmt::BasicStringWriter::move_to__std::basic_string:Char.std::char_traits:Char:.Allocator:R"></span><span class="target" id="formatclassfmt_1_1_basic_string_writer_1af5eb54db9a51ef610d55ecb858257fb0"></span>void <code class="descname">move_to</code><span class="sig-paren">(</span>std::basic_string<Char, std::char_traits<Char>, Allocator> &<em>str</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt17BasicStringWriter7move_toERNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Moves the buffer content to <em>str</em> clearing the buffer.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="class">
|
||||
<dt>
|
||||
<span class="target" id="formatclassfmt_1_1_basic_container_writer"></span><em class="property">template </em><<em class="property">class</em> Container></dt>
|
||||
<dt id="_CPPv2N3fmt20BasicContainerWriterE">
|
||||
<span id="fmt::BasicContainerWriter"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">BasicContainerWriter</code><a class="headerlink" href="#_CPPv2N3fmt20BasicContainerWriterE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>This class template provides operations for formatting and appending data
|
||||
to a standard <em>container</em> like <code class="docutils literal"><span class="pre">std::vector</span></code> or <code class="docutils literal"><span class="pre">std::basic_string</span></code>.</p>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">vecformat</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="kt">char</span><span class="o">>&</span> <span class="n">dest</span><span class="p">,</span> <span class="n">fmt</span><span class="o">::</span><span class="n">BasicCStringRef</span><span class="o"><</span><span class="kt">char</span><span class="o">></span> <span class="n">format</span><span class="p">,</span>
|
||||
<span class="n">fmt</span><span class="o">::</span><span class="n">ArgList</span> <span class="n">args</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="n">fmt</span><span class="o">::</span><span class="n">BasicContainerWriter</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="kt">char</span><span class="o">></span> <span class="o">></span> <span class="n">appender</span><span class="p">(</span><span class="n">dest</span><span class="p">);</span>
|
||||
<span class="n">appender</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">format</span><span class="p">,</span> <span class="n">args</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
<span class="n">FMT_VARIADIC</span><span class="p">(</span><span class="kt">void</span><span class="p">,</span> <span class="n">vecformat</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="kt">char</span><span class="o">>&</span><span class="p">,</span>
|
||||
<span class="n">fmt</span><span class="o">::</span><span class="n">BasicCStringRef</span><span class="o"><</span><span class="kt">char</span><span class="o">></span><span class="p">);</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</p>
|
||||
<p>Inherits from <a class="reference internal" href="#formatclassfmt_1_1_basic_writer"><span class="std std-ref">fmt::BasicWriter< Container::value_type ></span></a></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt20BasicContainerWriter20BasicContainerWriterER9Container">
|
||||
<span id="fmt::BasicContainerWriter::BasicContainerWriter__ContainerR"></span><span class="target" id="formatclassfmt_1_1_basic_container_writer_1a1c5f521af91a36bf07d580d3b5e8fde4"></span><code class="descname">BasicContainerWriter</code><span class="sig-paren">(</span>Container &<em>dest</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt20BasicContainerWriter20BasicContainerWriterER9Container" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Constructs a <a class="reference internal" href="#_CPPv2N3fmt20BasicContainerWriterE" title="fmt::BasicContainerWriter"><code class="xref cpp cpp-class docutils literal"><span class="pre">fmt::BasicContainerWriter</span></code></a> object.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt3binEi">
|
||||
<span id="fmt::bin__i"></span><span class="target" id="formatformat_8h_1aa3e8966d52b70224d46861fabd090e4b"></span>IntFormatSpec<int, TypeSpec<'b'>> <code class="descclassname">fmt::</code><code class="descname">bin</code><span class="sig-paren">(</span>int <em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt3binEi" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::bin__i"></span><span class="target" id="formatformat_8h_1a760fce6f0963895343b50eec787f80db"></span>IntFormatSpec<int, TypeSpec<'b'>> <code class="descclassname">fmt::</code><code class="descname">bin</code><span class="sig-paren">(</span>int <em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt3binEi" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns an integer format specifier to format the value in base 2. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt3octEi">
|
||||
<span id="fmt::oct__i"></span><span class="target" id="formatformat_8h_1a1d166c5b2242a6a0aefba5455c32a2b3"></span>IntFormatSpec<int, TypeSpec<'o'>> <code class="descclassname">fmt::</code><code class="descname">oct</code><span class="sig-paren">(</span>int <em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt3octEi" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::oct__i"></span><span class="target" id="formatformat_8h_1a49d07603108a758be5cc6157f456e32d"></span>IntFormatSpec<int, TypeSpec<'o'>> <code class="descclassname">fmt::</code><code class="descname">oct</code><span class="sig-paren">(</span>int <em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt3octEi" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns an integer format specifier to format the value in base 8. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt3hexEi">
|
||||
<span id="fmt::hex__i"></span><span class="target" id="formatformat_8h_1aaa926c5c42fbad5f5c98aaad84b9f66a"></span>IntFormatSpec<int, TypeSpec<'x'>> <code class="descclassname">fmt::</code><code class="descname">hex</code><span class="sig-paren">(</span>int <em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt3hexEi" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::hex__i"></span><span class="target" id="formatformat_8h_1a8451bad40c90c2ce2aa1a932851cf090"></span>IntFormatSpec<int, TypeSpec<'x'>> <code class="descclassname">fmt::</code><code class="descname">hex</code><span class="sig-paren">(</span>int <em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt3hexEi" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns an integer format specifier to format the value in base 16 using lower-case letters for the digits above 9. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt4hexuEi">
|
||||
<span id="fmt::hexu__i"></span><span class="target" id="formatformat_8h_1ac2fd8f73cfcd1321dfb6fb0302f23f66"></span>IntFormatSpec<int, TypeSpec<'X'>> <code class="descclassname">fmt::</code><code class="descname">hexu</code><span class="sig-paren">(</span>int <em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt4hexuEi" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::hexu__i"></span><span class="target" id="formatformat_8h_1ae08e783a599e0667dae7b5a63a265de4"></span>IntFormatSpec<int, TypeSpec<'X'>> <code class="descclassname">fmt::</code><code class="descname">hexu</code><span class="sig-paren">(</span>int <em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt4hexuEi" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns an integer formatter format specifier to format in base 16 using upper-case letters for the digits above 9. </p>
|
||||
</dd></dl>
|
||||
|
||||
@@ -797,7 +1042,7 @@ size known at compile time.</p>
|
||||
<dt>
|
||||
<em class="property">template </em><char <em>TYPE_CODE</em>, <em class="property">typename</em> Char></dt>
|
||||
<dt id="_CPPv2N3fmt3padEij4Char">
|
||||
<span id="fmt::pad__i.unsigned.Char"></span><span class="target" id="formatformat_8h_1a48d6010061d1710d807853ad9125d825"></span>IntFormatSpec<int, AlignTypeSpec<TYPE_CODE>, Char> <code class="descclassname">fmt::</code><code class="descname">pad</code><span class="sig-paren">(</span>int <em>value</em>, unsigned <em>width</em>, Char <em>fill</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt3padEij4Char" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::pad__i.unsigned.Char"></span><span class="target" id="formatformat_8h_1aa6ebb90e2adc57f2c942e226fd708b24"></span>IntFormatSpec<int, AlignTypeSpec<TYPE_CODE>, Char> <code class="descclassname">fmt::</code><code class="descname">pad</code><span class="sig-paren">(</span>int <em>value</em>, unsigned <em>width</em>, Char <em>fill</em> = ' '<span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt3padEij4Char" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Returns an integer format specifier to pad the formatted argument with the
|
||||
fill character to the specified width using the default (right) numeric
|
||||
alignment.</p>
|
||||
@@ -817,7 +1062,7 @@ alignment.</p>
|
||||
<dt>
|
||||
<em class="property">template </em><<em class="property">typename</em> T></dt>
|
||||
<dt id="_CPPv2N3fmt3argE9StringRefRK1T">
|
||||
<span id="fmt::arg__StringRef.TCR"></span><span class="target" id="formatformat_8h_1a4649a895b3f769fe24b268e39a8cf152"></span>internal::NamedArg<char> <code class="descclassname">fmt::</code><code class="descname">arg</code><span class="sig-paren">(</span>StringRef <em>name</em>, <em class="property">const</em> T &<em>arg</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt3argE9StringRefRK1T" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::arg__StringRef.TCR"></span><span class="target" id="formatformat_8h_1a3ccc93714460459602dc6fc2b055ee6b"></span>internal::NamedArgWithType<char, T> <code class="descclassname">fmt::</code><code class="descname">arg</code><span class="sig-paren">(</span>StringRef <em>name</em>, <em class="property">const</em> T &<em>arg</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt3argE9StringRefRK1T" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Returns a named argument for formatting functions.</p>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">print</span><span class="p">(</span><span class="s">"Elapsed time: {s:.2f} seconds"</span><span class="p">,</span> <span class="n">arg</span><span class="p">(</span><span class="s">"s"</span><span class="p">,</span> <span class="mf">1.23</span><span class="p">));</span>
|
||||
@@ -826,18 +1071,10 @@ alignment.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt8literalsli2_aEPKcNSt6size_tE">
|
||||
<span class="target" id="formatformat_8h_1a1f0ec67406a0e4937166e6481f481198"></span>internal::UdlArg<char> <code class="descclassname">fmt::literals::</code><code class="descname">operator""_a</code><span class="sig-paren">(</span><em class="property">const</em> char *<em>s</em>, std::size_t<span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt8literalsli2_aEPKcNSt6size_tE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>C++11 literal equivalent of <a class="reference internal" href="#_CPPv2N3fmt3argE9StringRefRK1T" title="fmt::arg"><code class="xref cpp cpp-func docutils literal"><span class="pre">fmt::arg()</span></code></a>.</p>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">using</span> <span class="k">namespace</span> <span class="n">fmt</span><span class="o">::</span><span class="n">literals</span><span class="p">;</span>
|
||||
<span class="n">print</span><span class="p">(</span><span class="s">"Elapsed time: {s:.2f} seconds"</span><span class="p">,</span> <span class="s">"s"</span><span class="n">_a</span><span class="o">=</span><span class="mf">1.23</span><span class="p">);</span>
|
||||
</pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="first admonition-title">Warning</p>
|
||||
<p class="last">doxygenfunction: Cannot find function “operator”“_a” in doxygen xml output for project “format” from directory: /home/foonathan/Programming/fmt/build/doc/doxyxml</p>
|
||||
</div>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="macro">
|
||||
<dt id="c.FMT_CAPTURE">
|
||||
<span class="target" id="formatformat_8h_1a3caa326fabdddb0e4fbcad7e5ec8bd37"></span><code class="descname">FMT_CAPTURE</code><span class="sig-paren">(</span>...<span class="sig-paren">)</span><a class="headerlink" href="#c.FMT_CAPTURE" title="Permalink to this definition">¶</a></dt>
|
||||
@@ -886,23 +1123,39 @@ directly:</p>
|
||||
<dt id="_CPPv2N3fmt7ArgListE">
|
||||
<span id="fmt::ArgList"></span><span class="target" id="formatclassfmt_1_1_arg_list"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">ArgList</code><a class="headerlink" href="#_CPPv2N3fmt7ArgListE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>An argument list. </p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt7ArgListixEj">
|
||||
<span id="fmt::ArgList::subscript-operator__unsigned"></span><span class="target" id="formatclassfmt_1_1_arg_list_1ad2c2672388e003aa70d9c948ac8140cd"></span>internal::Arg <code class="descname">operator[]</code><span class="sig-paren">(</span>unsigned <em>index</em><span class="sig-paren">)</span> const<a class="headerlink" href="#_CPPv2N3fmt7ArgListixEj" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2NK3fmt7ArgListixEj">
|
||||
<span id="fmt::ArgList::subscript-operator__unsignedC"></span><span class="target" id="formatclassfmt_1_1_arg_list_1a9a717b2022170c8f2918141a80cc6eb2"></span>internal::Arg <code class="descname">operator[]</code><span class="sig-paren">(</span>unsigned <em>index</em><span class="sig-paren">)</span> <em class="property">const</em><a class="headerlink" href="#_CPPv2NK3fmt7ArgListixEj" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns the argument at specified index. </p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<em class="property">template </em><<em class="property">typename</em> T></dt>
|
||||
<dt id="_CPPv2N3fmt9to_stringERK1T">
|
||||
<span id="fmt::to_string__TCR"></span><span class="target" id="formatstring_8h_1abfd84051cd3673d750be5851ee93b05f"></span>std::string <code class="descclassname">fmt::</code><code class="descname">to_string</code><span class="sig-paren">(</span><em class="property">const</em> T &<em>value</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt9to_stringERK1T" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Converts <em>value</em> to <code class="docutils literal"><span class="pre">std::string</span></code> using the default format for type <em>T</em>.</p>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">"fmt/string.h"</span><span class="cp"></span>
|
||||
|
||||
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">answer</span> <span class="o">=</span> <span class="n">fmt</span><span class="o">::</span><span class="n">to_string</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="class">
|
||||
<dt>
|
||||
<span class="target" id="formatclassfmt_1_1_basic_string_ref"></span><em class="property">template </em><typename <em>Char</em>></dt>
|
||||
<dt id="_CPPv2N3fmt14BasicStringRefE">
|
||||
<span id="fmt::BasicStringRef"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">BasicStringRef</code><a class="headerlink" href="#_CPPv2N3fmt14BasicStringRefE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>A string reference. It can be constructed from a C string or <code class="docutils literal"><span class="pre">std::string</span></code>.</p>
|
||||
<dd><p><p>A string reference. It can be constructed from a C string or
|
||||
<code class="docutils literal"><span class="pre">std::basic_string</span></code>.</p>
|
||||
<p>You can use one of the following typedefs for common character types:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
@@ -933,7 +1186,7 @@ different types of strings to a function, for example:</p>
|
||||
</pre></div>
|
||||
</div>
|
||||
</p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt14BasicStringRef14BasicStringRefEPK4CharNSt6size_tE">
|
||||
@@ -950,28 +1203,30 @@ the size with <code class="docutils literal"><span class="pre">std::char_traits&
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt14BasicStringRef14BasicStringRefERKNSt12basic_stringI4CharEE">
|
||||
<span id="fmt::BasicStringRef::BasicStringRef__std::basic_string:Char:CR"></span><span class="target" id="formatclassfmt_1_1_basic_string_ref_1afd8ffd0c6d2ccac657f277a4faea3889"></span><code class="descname">BasicStringRef</code><span class="sig-paren">(</span><em class="property">const</em> std::basic_string<Char> &<em>s</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt14BasicStringRef14BasicStringRefERKNSt12basic_stringI4CharEE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Constructs a string reference from an <code class="docutils literal"><span class="pre">std::string</span></code> object.</p>
|
||||
<dt>
|
||||
<em class="property">template </em><<em class="property">typename</em> Allocator></dt>
|
||||
<dt id="_CPPv2N3fmt14BasicStringRef14BasicStringRefERKNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE">
|
||||
<span id="fmt::BasicStringRef::BasicStringRef__std::basic_string:Char.std::char_traits:Char:.Allocator:CR"></span><span class="target" id="formatclassfmt_1_1_basic_string_ref_1a7c4c0c3bfc4768d7cb657f5756549863"></span><code class="descname">BasicStringRef</code><span class="sig-paren">(</span><em class="property">const</em> std::basic_string<Char, std::char_traits<Char>, Allocator> &<em>s</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt14BasicStringRef14BasicStringRefERKNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Constructs a string reference from a <code class="docutils literal"><span class="pre">std::basic_string</span></code> object.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt14BasicStringRef9to_stringEv">
|
||||
<span id="fmt::BasicStringRef::to_string"></span><span class="target" id="formatclassfmt_1_1_basic_string_ref_1a7340f48f53cf9188e9fea5e6e1556969"></span>std::basic_string<Char> <code class="descname">to_string</code><span class="sig-paren">(</span><span class="sig-paren">)</span> const<a class="headerlink" href="#_CPPv2N3fmt14BasicStringRef9to_stringEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2NK3fmt14BasicStringRef9to_stringEv">
|
||||
<span id="fmt::BasicStringRef::to_stringC"></span><span class="target" id="formatclassfmt_1_1_basic_string_ref_1a85503c30cd35cd6deff9e77da52857e6"></span>std::basic_string<Char> <code class="descname">to_string</code><span class="sig-paren">(</span><span class="sig-paren">)</span> <em class="property">const</em><a class="headerlink" href="#_CPPv2NK3fmt14BasicStringRef9to_stringEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Converts a string reference to an <code class="docutils literal"><span class="pre">std::string</span></code> object.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt14BasicStringRef4dataEv">
|
||||
<span id="fmt::BasicStringRef::data"></span><span class="target" id="formatclassfmt_1_1_basic_string_ref_1ae9c80502c527437215fe1c11dca8b475"></span><em class="property">const</em> Char *<code class="descname">data</code><span class="sig-paren">(</span><span class="sig-paren">)</span> const<a class="headerlink" href="#_CPPv2N3fmt14BasicStringRef4dataEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2NK3fmt14BasicStringRef4dataEv">
|
||||
<span id="fmt::BasicStringRef::dataC"></span><span class="target" id="formatclassfmt_1_1_basic_string_ref_1aeca62faae1111525b0ef2667e75187f7"></span><em class="property">const</em> Char *<code class="descname">data</code><span class="sig-paren">(</span><span class="sig-paren">)</span> <em class="property">const</em><a class="headerlink" href="#_CPPv2NK3fmt14BasicStringRef4dataEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns a pointer to the string data. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt14BasicStringRef4sizeEv">
|
||||
<span id="fmt::BasicStringRef::size"></span><span class="target" id="formatclassfmt_1_1_basic_string_ref_1ae38d9106dd5bec69488e5464aedc266a"></span>std::size_t <code class="descname">size</code><span class="sig-paren">(</span><span class="sig-paren">)</span> const<a class="headerlink" href="#_CPPv2N3fmt14BasicStringRef4sizeEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2NK3fmt14BasicStringRef4sizeEv">
|
||||
<span id="fmt::BasicStringRef::sizeC"></span><span class="target" id="formatclassfmt_1_1_basic_string_ref_1a765ddcb00e0a0a880a4a9458f9e68ea0"></span>std::size_t <code class="descname">size</code><span class="sig-paren">(</span><span class="sig-paren">)</span> <em class="property">const</em><a class="headerlink" href="#_CPPv2NK3fmt14BasicStringRef4sizeEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns the string size. </p>
|
||||
</dd></dl>
|
||||
|
||||
@@ -984,7 +1239,7 @@ the size with <code class="docutils literal"><span class="pre">std::char_traits&
|
||||
<dt id="_CPPv2N3fmt15BasicCStringRefE">
|
||||
<span id="fmt::BasicCStringRef"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">BasicCStringRef</code><a class="headerlink" href="#_CPPv2N3fmt15BasicCStringRefE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>A reference to a null terminated string. It can be constructed from a C
|
||||
string or <code class="docutils literal"><span class="pre">std::string</span></code>.</p>
|
||||
string or <code class="docutils literal"><span class="pre">std::basic_string</span></code>.</p>
|
||||
<p>You can use one of the following typedefs for common character types:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
@@ -1015,7 +1270,7 @@ different types of strings to a function, for example:</p>
|
||||
</pre></div>
|
||||
</div>
|
||||
</p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt15BasicCStringRef15BasicCStringRefEPK4Char">
|
||||
@@ -1024,15 +1279,17 @@ different types of strings to a function, for example:</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt15BasicCStringRef15BasicCStringRefERKNSt12basic_stringI4CharEE">
|
||||
<span id="fmt::BasicCStringRef::BasicCStringRef__std::basic_string:Char:CR"></span><span class="target" id="formatclassfmt_1_1_basic_c_string_ref_1ab460855d19c769773de532296f9f13f9"></span><code class="descname">BasicCStringRef</code><span class="sig-paren">(</span><em class="property">const</em> std::basic_string<Char> &<em>s</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt15BasicCStringRef15BasicCStringRefERKNSt12basic_stringI4CharEE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Constructs a string reference from an <code class="docutils literal"><span class="pre">std::string</span></code> object.</p>
|
||||
<dt>
|
||||
<em class="property">template </em><<em class="property">typename</em> Allocator></dt>
|
||||
<dt id="_CPPv2N3fmt15BasicCStringRef15BasicCStringRefERKNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE">
|
||||
<span id="fmt::BasicCStringRef::BasicCStringRef__std::basic_string:Char.std::char_traits:Char:.Allocator:CR"></span><span class="target" id="formatclassfmt_1_1_basic_c_string_ref_1aa7caaa44a192e0184031d60c2a71bd12"></span><code class="descname">BasicCStringRef</code><span class="sig-paren">(</span><em class="property">const</em> std::basic_string<Char, std::char_traits<Char>, Allocator> &<em>s</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt15BasicCStringRef15BasicCStringRefERKNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Constructs a string reference from a <code class="docutils literal"><span class="pre">std::basic_string</span></code> object.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt15BasicCStringRef5c_strEv">
|
||||
<span id="fmt::BasicCStringRef::c_str"></span><span class="target" id="formatclassfmt_1_1_basic_c_string_ref_1ae3bafa845b53339b20c4f5edb4f635f9"></span><em class="property">const</em> Char *<code class="descname">c_str</code><span class="sig-paren">(</span><span class="sig-paren">)</span> const<a class="headerlink" href="#_CPPv2N3fmt15BasicCStringRef5c_strEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2NK3fmt15BasicCStringRef5c_strEv">
|
||||
<span id="fmt::BasicCStringRef::c_strC"></span><span class="target" id="formatclassfmt_1_1_basic_c_string_ref_1ac1064b18371a8762e3d89395d253d436"></span><em class="property">const</em> Char *<code class="descname">c_str</code><span class="sig-paren">(</span><span class="sig-paren">)</span> <em class="property">const</em><a class="headerlink" href="#_CPPv2NK3fmt15BasicCStringRef5c_strEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns the pointer to a C string. </p>
|
||||
</dd></dl>
|
||||
|
||||
@@ -1046,17 +1303,18 @@ different types of strings to a function, for example:</p>
|
||||
<span id="fmt::Buffer"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">Buffer</code><a class="headerlink" href="#_CPPv2N3fmt6BufferE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>A buffer supporting a subset of <code class="docutils literal"><span class="pre">std::vector</span></code>‘s operations.</p>
|
||||
</p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<p>Subclassed by fmt::internal::MemoryBuffer< T, SIZE, Allocator ></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt6Buffer4sizeEv">
|
||||
<span id="fmt::Buffer::size"></span><span class="target" id="formatclassfmt_1_1_buffer_1a14fa72f0ddf584c14ffffb1446f598aa"></span>std::size_t <code class="descname">size</code><span class="sig-paren">(</span><span class="sig-paren">)</span> const<a class="headerlink" href="#_CPPv2N3fmt6Buffer4sizeEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2NK3fmt6Buffer4sizeEv">
|
||||
<span id="fmt::Buffer::sizeC"></span><span class="target" id="formatclassfmt_1_1_buffer_1a2489cffd9cdc6f846cdf17988d52f785"></span>std::size_t <code class="descname">size</code><span class="sig-paren">(</span><span class="sig-paren">)</span> <em class="property">const</em><a class="headerlink" href="#_CPPv2NK3fmt6Buffer4sizeEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns the size of this buffer. </p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt6Buffer8capacityEv">
|
||||
<span id="fmt::Buffer::capacity"></span><span class="target" id="formatclassfmt_1_1_buffer_1aaf54fe786de91157629f96380e0cb215"></span>std::size_t <code class="descname">capacity</code><span class="sig-paren">(</span><span class="sig-paren">)</span> const<a class="headerlink" href="#_CPPv2N3fmt6Buffer8capacityEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dt id="_CPPv2NK3fmt6Buffer8capacityEv">
|
||||
<span id="fmt::Buffer::capacityC"></span><span class="target" id="formatclassfmt_1_1_buffer_1af38a0b9f1afac4901f24a73207f72e6f"></span>std::size_t <code class="descname">capacity</code><span class="sig-paren">(</span><span class="sig-paren">)</span> <em class="property">const</em><a class="headerlink" href="#_CPPv2NK3fmt6Buffer8capacityEv" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns the capacity of this buffer. </p>
|
||||
</dd></dl>
|
||||
|
||||
@@ -1083,11 +1341,11 @@ different types of strings to a function, for example:</p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
<div class="breathe-sectiondef container">
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Protected Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt6Buffer4growENSt6size_tE">
|
||||
<span id="fmt::Buffer::grow__std::s"></span>virtual <span class="target" id="formatclassfmt_1_1_buffer_1abdc7aaf5813aa07008b3d715969a7e19"></span>void <code class="descname">grow</code><span class="sig-paren">(</span>std::size_t <em>size</em><span class="sig-paren">)</span> = 0<a class="headerlink" href="#_CPPv2N3fmt6Buffer4growENSt6size_tE" title="Permalink to this definition">¶</a></dt>
|
||||
<span id="fmt::Buffer::grow__std::s"></span><span class="target" id="formatclassfmt_1_1_buffer_1abdc7aaf5813aa07008b3d715969a7e19"></span><em class="property">virtual</em> void <code class="descname">grow</code><span class="sig-paren">(</span>std::size_t <em>size</em><span class="sig-paren">)</span> = 0<a class="headerlink" href="#_CPPv2N3fmt6Buffer4growENSt6size_tE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Increases the buffer capacity to hold at least <em>size</em> elements updating
|
||||
<code class="docutils literal"><span class="pre">ptr_</span></code> and <code class="docutils literal"><span class="pre">capacity_</span></code>.</p>
|
||||
</p>
|
||||
@@ -1103,21 +1361,17 @@ different types of strings to a function, for example:</p>
|
||||
<dt id="_CPPv2N3fmt11SystemErrorE">
|
||||
<span id="fmt::SystemError"></span><span class="target" id="formatclassfmt_1_1_system_error"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">SystemError</code><a class="headerlink" href="#_CPPv2N3fmt11SystemErrorE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>An error returned by an operating system or a language runtime, for example a file opening error. </p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<p>Inherits from fmt::internal::RuntimeError</p>
|
||||
<p>Subclassed by <a class="reference internal" href="#formatclassfmt_1_1_windows_error"><span class="std std-ref">fmt::WindowsError</span></a></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt11SystemError11SystemErrorEi10CStringRef">
|
||||
<span id="fmt::SystemError::SystemError__i.CStringRef"></span><span class="target" id="formatclassfmt_1_1_system_error_1a307c40b2542f53d7426b09319255d35c"></span><code class="descname">SystemError</code><span class="sig-paren">(</span>int <em>error_code</em>, CStringRef <em>message</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt11SystemError11SystemErrorEi10CStringRef" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Constructs a <a class="reference internal" href="#_CPPv2N3fmt11SystemErrorE" title="fmt::SystemError"><code class="xref cpp cpp-class docutils literal"><span class="pre">fmt::SystemError</span></code></a> object with the description
|
||||
of the form</p>
|
||||
<pre class="literal-block">
|
||||
<em><message></em>: <em><system-message></em>
|
||||
</pre>
|
||||
<p>where <em><message></em> is the formatted message and <em><system-message></em> is
|
||||
the system message corresponding to the error code.
|
||||
<em>error_code</em> is a system error code as given by <code class="docutils literal"><span class="pre">errno</span></code>.
|
||||
If <em>error_code</em> is not a valid error code such as -1, the system message
|
||||
may look like “Unknown error -1” and is platform-dependent.</p>
|
||||
<dd><p><p>Constructs a <a class="reference internal" href="#_CPPv2N3fmt11SystemErrorE" title="fmt::SystemError"><code class="xref cpp cpp-class docutils literal"><span class="pre">fmt::SystemError</span></code></a> object with a description
|
||||
formatted with <a class="reference internal" href="#_CPPv2N3fmt19format_system_errorERN3fmt6WriterEiN3fmt9StringRefE" title="fmt::format_system_error"><code class="xref cpp cpp-any docutils literal"><span class="pre">fmt::format_system_error()</span></code></a>. <em>message</em> and additional
|
||||
arguments passed into the constructor are formatted similarly to
|
||||
<a class="reference internal" href="#_CPPv2N3fmt6formatE10CStringRef7ArgList" title="fmt::format"><code class="xref cpp cpp-any docutils literal"><span class="pre">fmt::format()</span></code></a>.</p>
|
||||
<p><strong>Example</strong>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="c1">// This throws a SystemError with the description</span>
|
||||
<span class="c1">// cannot open file 'madeup': No such file or directory</span>
|
||||
@@ -1134,11 +1388,29 @@ may look like “Unknown error -1” and is platform-dependent.</p>
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt19format_system_errorERN3fmt6WriterEiN3fmt9StringRefE">
|
||||
<span id="fmt::format_system_error__fmt::WriterR.i.fmt::StringRef"></span><span class="target" id="formatformat_8h_1a3933879503d45e8cce0ef1e284f98402"></span>void <code class="descclassname">fmt::</code><code class="descname">format_system_error</code><span class="sig-paren">(</span>fmt::Writer &<em>out</em>, int <em>error_code</em>, fmt::StringRef <em>message</em><span class="sig-paren">)</span><a class="headerlink" href="#_CPPv2N3fmt19format_system_errorERN3fmt6WriterEiN3fmt9StringRefE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p><p>Formats an error returned by an operating system or a language runtime,
|
||||
for example a file opening error, and writes it to <em>out</em> in the following
|
||||
form:</p>
|
||||
<pre class="literal-block">
|
||||
<em><message></em>: <em><system-message></em>
|
||||
</pre>
|
||||
<p>where <em><message></em> is the passed message and <em><system-message></em> is
|
||||
the system message corresponding to the error code.
|
||||
<em>error_code</em> is a system error code as given by <code class="docutils literal"><span class="pre">errno</span></code>.
|
||||
If <em>error_code</em> is not a valid error code such as -1, the system message
|
||||
may look like “Unknown error -1” and is platform-dependent.</p>
|
||||
</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="class">
|
||||
<dt id="_CPPv2N3fmt12WindowsErrorE">
|
||||
<span id="fmt::WindowsError"></span><span class="target" id="formatclassfmt_1_1_windows_error"></span><em class="property">class </em><code class="descclassname">fmt::</code><code class="descname">WindowsError</code><a class="headerlink" href="#_CPPv2N3fmt12WindowsErrorE" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>A Windows error. </p>
|
||||
<div class="breathe-sectiondef container">
|
||||
<p>Inherits from <a class="reference internal" href="#formatclassfmt_1_1_system_error"><span class="std std-ref">fmt::SystemError</span></a></p>
|
||||
<div class="breathe-sectiondef docutils container">
|
||||
<p class="breathe-sectiondef-title rubric">Public Functions</p>
|
||||
<dl class="function">
|
||||
<dt id="_CPPv2N3fmt12WindowsError12WindowsErrorEi10CStringRef">
|
||||
@@ -1183,7 +1455,8 @@ A custom allocator class can be specified as a template argument to
|
||||
</div>
|
||||
<p>It is also possible to write a formatting function that uses a custom
|
||||
allocator:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">basic_string</span><span class="o"><</span><span class="kt">char</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">char_traits</span><span class="o"><</span><span class="kt">char</span><span class="o">></span><span class="p">,</span> <span class="n">CustomAllocator</span><span class="o">></span> <span class="n">CustomString</span><span class="p">;</span>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">basic_string</span><span class="o"><</span><span class="kt">char</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">char_traits</span><span class="o"><</span><span class="kt">char</span><span class="o">></span><span class="p">,</span> <span class="n">CustomAllocator</span><span class="o">></span>
|
||||
<span class="n">CustomString</span><span class="p">;</span>
|
||||
|
||||
<span class="n">CustomString</span> <span class="nf">format</span><span class="p">(</span><span class="n">CustomAllocator</span> <span class="n">alloc</span><span class="p">,</span> <span class="n">fmt</span><span class="o">::</span><span class="n">CStringRef</span> <span class="n">format_str</span><span class="p">,</span>
|
||||
<span class="n">fmt</span><span class="o">::</span><span class="n">ArgList</span> <span class="n">args</span><span class="p">)</span> <span class="p">{</span>
|
||||
@@ -1206,7 +1479,7 @@ allocator:</p>
|
||||
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2012-2015, Victor Zverovich.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
|
||||
</div>
|
||||
|
||||
<script src="_static/bootstrap.min.js"></script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
|
||||
<title>Contents — fmt 3.0.0 documentation</title>
|
||||
<title>Contents — fmt 4.0.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@@ -17,10 +17,11 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: './',
|
||||
VERSION: '3.0.0',
|
||||
VERSION: '4.0.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
HAS_SOURCE: true,
|
||||
SOURCELINK_SUFFIX: ''
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
@@ -34,8 +35,9 @@
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();
|
||||
a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;
|
||||
a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-20116650-4', 'fmtlib.net');
|
||||
ga('send', 'pageview');
|
||||
@@ -49,7 +51,8 @@
|
||||
<div class="navbar-content">
|
||||
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -62,18 +65,23 @@
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||
aria-expanded="false">3.0.0 <span class="caret"></span></a>
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
|
||||
role="button" aria-expanded="false">4.0.0
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="http://fmtlib.net/2.0.0/">2.0.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.1.0/">1.1.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.0.0/">1.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/3.0.0">3.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/2.0.0">2.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/1.1.0">1.1.0</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
<li class="active"><a href="contents.html">Contents <span class="sr-only">(current)</span></a></li>
|
||||
<li class="active"><a href="contents.html">Contents
|
||||
<span class="sr-only">(current)</span></a></li>
|
||||
|
||||
|
||||
|
||||
@@ -91,9 +99,11 @@
|
||||
</ul>
|
||||
|
||||
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html" method="get">
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html"
|
||||
method="get">
|
||||
<div class="form-group">
|
||||
<input type="text" name="q" class="form-control" placeholder="Search" >
|
||||
<input type="text" name="q" class="form-control"
|
||||
placeholder="Search" >
|
||||
</div>
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
@@ -120,6 +130,7 @@
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="usage.html">Usage</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#building-the-library">Building the library</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#header-only-usage-with-cmake">Header-only usage with CMake</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#building-the-documentation">Building the documentation</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#android-ndk">Android NDK</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#homebrew">Homebrew</a></li>
|
||||
@@ -151,7 +162,7 @@
|
||||
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2012-2015, Victor Zverovich.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
|
||||
</div>
|
||||
|
||||
<script src="_static/bootstrap.min.js"></script>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
|
||||
<title>Index — fmt 3.0.0 documentation</title>
|
||||
<title>Index — fmt 4.0.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@@ -18,10 +18,11 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: './',
|
||||
VERSION: '3.0.0',
|
||||
VERSION: '4.0.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
HAS_SOURCE: true,
|
||||
SOURCELINK_SUFFIX: ''
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
@@ -34,8 +35,9 @@
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();
|
||||
a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;
|
||||
a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-20116650-4', 'fmtlib.net');
|
||||
ga('send', 'pageview');
|
||||
@@ -49,7 +51,8 @@
|
||||
<div class="navbar-content">
|
||||
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -62,13 +65,17 @@
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||
aria-expanded="false">3.0.0 <span class="caret"></span></a>
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
|
||||
role="button" aria-expanded="false">4.0.0
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="http://fmtlib.net/2.0.0/">2.0.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.1.0/">1.1.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.0.0/">1.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/3.0.0">3.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/2.0.0">2.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/1.1.0">1.1.0</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -91,9 +98,11 @@
|
||||
</ul>
|
||||
|
||||
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html" method="get">
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html"
|
||||
method="get">
|
||||
<div class="form-group">
|
||||
<input type="text" name="q" class="form-control" placeholder="Search" >
|
||||
<input type="text" name="q" class="form-control"
|
||||
placeholder="Search" >
|
||||
</div>
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
@@ -141,7 +150,7 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt7ArgListixEj">fmt::ArgList::operator[] (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2NK3fmt7ArgListixEj">fmt::ArgList::operator[] (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
@@ -217,7 +226,7 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt17BasicArgFormatter17BasicArgFormatterER14BasicFormatterI4Char4ImplER10FormatSpecPK4Char">fmt::BasicArgFormatter::BasicArgFormatter (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2N3fmt17BasicArgFormatter17BasicArgFormatterER14BasicFormatterI4Char4ImplER4SpecPK4Char">fmt::BasicArgFormatter::BasicArgFormatter (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
@@ -233,15 +242,23 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt20BasicContainerWriterE">fmt::BasicContainerWriter (C++ class)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt20BasicContainerWriter20BasicContainerWriterER9Container">fmt::BasicContainerWriter::BasicContainerWriter (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt15BasicCStringRefE">fmt::BasicCStringRef (C++ class)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt15BasicCStringRef15BasicCStringRefEPK4Char">fmt::BasicCStringRef::BasicCStringRef (C++ function)</a>, <a href="api.html#_CPPv2N3fmt15BasicCStringRef15BasicCStringRefERKNSt12basic_stringI4CharEE">[1]</a>
|
||||
<dt><a href="api.html#_CPPv2N3fmt15BasicCStringRef15BasicCStringRefEPK4Char">fmt::BasicCStringRef::BasicCStringRef (C++ function)</a>, <a href="api.html#_CPPv2N3fmt15BasicCStringRef15BasicCStringRefERKNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE">[1]</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt15BasicCStringRef5c_strEv">fmt::BasicCStringRef::c_str (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2NK3fmt15BasicCStringRef5c_strEv">fmt::BasicCStringRef::c_str (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
@@ -276,6 +293,34 @@
|
||||
<dt><a href="api.html#_CPPv2N3fmt17BasicMemoryWriteraSERR17BasicMemoryWriter">fmt::BasicMemoryWriter::operator= (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt23BasicPrintfArgFormatterE">fmt::BasicPrintfArgFormatter (C++ class)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt23BasicPrintfArgFormatter23BasicPrintfArgFormatterER11BasicWriterI4CharER4Spec">fmt::BasicPrintfArgFormatter::BasicPrintfArgFormatter (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt23BasicPrintfArgFormatter10visit_boolEb">fmt::BasicPrintfArgFormatter::visit_bool (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt23BasicPrintfArgFormatter10visit_charEi">fmt::BasicPrintfArgFormatter::visit_char (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt23BasicPrintfArgFormatter13visit_cstringEPKc">fmt::BasicPrintfArgFormatter::visit_cstring (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt23BasicPrintfArgFormatter12visit_customEN8internal3Arg11CustomValueE">fmt::BasicPrintfArgFormatter::visit_custom (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt23BasicPrintfArgFormatter13visit_pointerEPKv">fmt::BasicPrintfArgFormatter::visit_pointer (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
</dl></td>
|
||||
<td style="width: 33%" valign="top"><dl>
|
||||
|
||||
@@ -283,19 +328,31 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt14BasicStringRef14BasicStringRefEPK4Char">fmt::BasicStringRef::BasicStringRef (C++ function)</a>, <a href="api.html#_CPPv2N3fmt14BasicStringRef14BasicStringRefEPK4CharNSt6size_tE">[1]</a>, <a href="api.html#_CPPv2N3fmt14BasicStringRef14BasicStringRefERKNSt12basic_stringI4CharEE">[2]</a>
|
||||
<dt><a href="api.html#_CPPv2N3fmt14BasicStringRef14BasicStringRefEPK4Char">fmt::BasicStringRef::BasicStringRef (C++ function)</a>, <a href="api.html#_CPPv2N3fmt14BasicStringRef14BasicStringRefEPK4CharNSt6size_tE">[1]</a>, <a href="api.html#_CPPv2N3fmt14BasicStringRef14BasicStringRefERKNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE">[2]</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt14BasicStringRef4dataEv">fmt::BasicStringRef::data (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2NK3fmt14BasicStringRef4dataEv">fmt::BasicStringRef::data (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt14BasicStringRef4sizeEv">fmt::BasicStringRef::size (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2NK3fmt14BasicStringRef4sizeEv">fmt::BasicStringRef::size (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt14BasicStringRef9to_stringEv">fmt::BasicStringRef::to_string (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2NK3fmt14BasicStringRef9to_stringEv">fmt::BasicStringRef::to_string (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt17BasicStringWriterE">fmt::BasicStringWriter (C++ class)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt17BasicStringWriter17BasicStringWriterERK9Allocator">fmt::BasicStringWriter::BasicStringWriter (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt17BasicStringWriter7move_toERNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE">fmt::BasicStringWriter::move_to (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
@@ -303,11 +360,11 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt11BasicWriter5c_strEv">fmt::BasicWriter::c_str (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2NK3fmt11BasicWriter5c_strEv">fmt::BasicWriter::c_str (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt11BasicWriter4dataEv">fmt::BasicWriter::data (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2NK3fmt11BasicWriter4dataEv">fmt::BasicWriter::data (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
@@ -315,11 +372,11 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt11BasicWriter4sizeEv">fmt::BasicWriter::size (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2NK3fmt11BasicWriter4sizeEv">fmt::BasicWriter::size (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt11BasicWriter3strEv">fmt::BasicWriter::str (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2NK3fmt11BasicWriter3strEv">fmt::BasicWriter::str (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
@@ -343,7 +400,7 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt6Buffer8capacityEv">fmt::Buffer::capacity (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2NK3fmt6Buffer8capacityEv">fmt::Buffer::capacity (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
@@ -359,7 +416,7 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt6Buffer4sizeEv">fmt::Buffer::size (C++ function)</a>
|
||||
<dt><a href="api.html#_CPPv2NK3fmt6Buffer4sizeEv">fmt::Buffer::size (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
@@ -367,6 +424,10 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt19format_system_errorERN3fmt6WriterEiN3fmt9StringRefE">fmt::format_system_error (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt7fprintfEPNSt4FILEE10CStringRef7ArgList">fmt::fprintf (C++ function)</a>, <a href="api.html#_CPPv2N3fmt7fprintfERNSt7ostreamE10CStringRef7ArgList">[1]</a>
|
||||
</dt>
|
||||
|
||||
@@ -379,14 +440,6 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt8literalsli2_aEPKcNSt6size_tE">fmt::literals::operator""_a (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt8literalsli7_formatEPKcNSt6size_tE">fmt::literals::operator""_format (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt3octEi">fmt::oct (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
@@ -403,6 +456,26 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt18PrintfArgFormatterE">fmt::PrintfArgFormatter (C++ class)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt18PrintfArgFormatter18PrintfArgFormatterER11BasicWriterI4CharER10FormatSpec">fmt::PrintfArgFormatter::PrintfArgFormatter (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt15PrintfFormatterE">fmt::PrintfFormatter (C++ class)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt15PrintfFormatter6formatE15BasicCStringRefI4CharE">fmt::PrintfFormatter::format (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt15PrintfFormatter15PrintfFormatterERK7ArgListR11BasicWriterI4CharE">fmt::PrintfFormatter::PrintfFormatter (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt7sprintfE10CStringRef7ArgList">fmt::sprintf (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
@@ -415,6 +488,10 @@
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt9to_stringERK1T">fmt::to_string (C++ function)</a>
|
||||
</dt>
|
||||
|
||||
|
||||
<dt><a href="api.html#_CPPv2N3fmt12WindowsErrorE">fmt::WindowsError (C++ class)</a>
|
||||
</dt>
|
||||
|
||||
@@ -443,7 +520,7 @@
|
||||
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2012-2015, Victor Zverovich.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
|
||||
</div>
|
||||
|
||||
<script src="_static/bootstrap.min.js"></script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
|
||||
<title>Overview — fmt 3.0.0 documentation</title>
|
||||
<title>Overview — fmt 4.0.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@@ -17,10 +17,11 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: './',
|
||||
VERSION: '3.0.0',
|
||||
VERSION: '4.0.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
HAS_SOURCE: true,
|
||||
SOURCELINK_SUFFIX: ''
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
@@ -33,8 +34,9 @@
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();
|
||||
a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;
|
||||
a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-20116650-4', 'fmtlib.net');
|
||||
ga('send', 'pageview');
|
||||
@@ -48,7 +50,8 @@
|
||||
<div class="navbar-content">
|
||||
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -61,13 +64,17 @@
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||
aria-expanded="false">3.0.0 <span class="caret"></span></a>
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
|
||||
role="button" aria-expanded="false">4.0.0
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="http://fmtlib.net/2.0.0/">2.0.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.1.0/">1.1.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.0.0/">1.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/3.0.0">3.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/2.0.0">2.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/1.1.0">1.1.0</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -90,9 +97,11 @@
|
||||
</ul>
|
||||
|
||||
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html" method="get">
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html"
|
||||
method="get">
|
||||
<div class="form-group">
|
||||
<input type="text" name="q" class="form-control" placeholder="Search" >
|
||||
<input type="text" name="q" class="form-control"
|
||||
placeholder="Search" >
|
||||
</div>
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
@@ -105,20 +114,33 @@
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="jumbotron">
|
||||
<div class="tb-container">
|
||||
<h1>{fmt}</h1>
|
||||
<p class="lead">Small, safe and fast formatting library</p>
|
||||
<div class="btn-group" role="group">
|
||||
|
||||
<a class="btn btn-success"
|
||||
href="https://github.com/fmtlib/fmt/releases/download/2.0.0/cppformat-2.0.0.zip">
|
||||
<span class="glyphicon glyphicon-download"></span> Download
|
||||
href="https://github.com/fmtlib/fmt/releases/download/4.0.0/fmt-4.0.0.zip">
|
||||
<span class="glyphicon glyphicon-download"></span> Download
|
||||
</a>
|
||||
<button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
|
||||
<button type="button" class="btn btn-success dropdown-toggle"
|
||||
data-toggle="dropdown"><span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="https://github.com/fmtlib/fmt/releases/download/2.0.0/cppformat-2.0.0.zip">Version 2.0.0</a></li>
|
||||
<li><a href="https://github.com/fmtlib/fmt/releases/download/1.1.0/cppformat-1.1.0.zip">Version 1.1.0</a></li>
|
||||
<li><a href="https://github.com/fmtlib/fmt/releases/download/1.0.0/cppformat-1.0.0.zip">Version 1.0.0</a></li>
|
||||
|
||||
|
||||
<li><a href="https://github.com/fmtlib/fmt/releases/download/3.0.0/fmt-3.0.0.zip">Version 3.0.0
|
||||
</a></li>
|
||||
|
||||
|
||||
<li><a href="https://github.com/fmtlib/fmt/releases/download/2.0.0/cppformat-2.0.0.zip">Version 2.0.0
|
||||
</a></li>
|
||||
|
||||
|
||||
<li><a href="https://github.com/fmtlib/fmt/releases/download/1.1.0/cppformat-1.1.0.zip">Version 1.1.0
|
||||
</a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -140,16 +162,16 @@ alternative to C++ IOStreams.</p>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">What users say:</div>
|
||||
<div class="panel-body">
|
||||
Thanks for creating this library. It’s been a hole in C++ for a long time.
|
||||
I’ve used both boost::format and loki::SPrintf, and neither felt like the
|
||||
right answer. This does.
|
||||
Thanks for creating this library. It’s been a hole in C++ for a long
|
||||
time. I’ve used both boost::format and loki::SPrintf, and neither felt
|
||||
like the right answer. This does.
|
||||
</div>
|
||||
</div><div class="section" id="format-api">
|
||||
<span id="id1"></span><h2>Format API<a class="headerlink" href="#format-api" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The replacement-based Format API provides a safe alternative to <code class="docutils literal"><span class="pre">printf</span></code>,
|
||||
<code class="docutils literal"><span class="pre">sprintf</span></code> and friends with comparable or <a class="reference external" href="http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html">better performance</a>.
|
||||
The <a class="reference external" href="doc/latest/index.html#format-string-syntax">format string syntax</a> is similar
|
||||
to the one used by <a class="reference external" href="http://docs.python.org/2/library/stdtypes.html#str.format">str.format</a>
|
||||
The <a class="reference external" href="syntax.html">format string syntax</a> is similar to the one used by
|
||||
<a class="reference external" href="http://docs.python.org/2/library/stdtypes.html#str.format">str.format</a>
|
||||
in Python:</p>
|
||||
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">"The answer is {}"</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span>
|
||||
</pre></div>
|
||||
@@ -202,8 +224,7 @@ literal operators, they must be made visible with the directive
|
||||
</div>
|
||||
<div class="section" id="write-api">
|
||||
<span id="id2"></span><h2>Write API<a class="headerlink" href="#write-api" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The concatenation-based Write API (experimental) provides a
|
||||
<a class="reference external" href="http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html">fast</a>
|
||||
<p>The concatenation-based Write API (experimental) provides a <a class="reference external" href="http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html">fast</a>
|
||||
stateless alternative to IOStreams:</p>
|
||||
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">MemoryWriter</span> <span class="n">out</span><span class="p">;</span>
|
||||
<span class="n">out</span> <span class="o"><<</span> <span class="s">"The answer in hexadecimal is "</span> <span class="o"><<</span> <span class="n">hex</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span>
|
||||
@@ -212,8 +233,9 @@ stateless alternative to IOStreams:</p>
|
||||
</div>
|
||||
<div class="section" id="safety">
|
||||
<span id="id3"></span><h2>Safety<a class="headerlink" href="#safety" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The library is fully type safe, automatic memory management prevents buffer overflow,
|
||||
errors in format strings are reported using exceptions. For example, the code</p>
|
||||
<p>The library is fully type safe, automatic memory management prevents buffer
|
||||
overflow, errors in format strings are reported using exceptions. For example,
|
||||
the code</p>
|
||||
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">"The answer is {:d}"</span><span class="p">,</span> <span class="s">"forty-two"</span><span class="p">);</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
@@ -231,36 +253,38 @@ formatted into a narrow string. You can use a wide format string instead:</p>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>For comparison, writing a wide character to <code class="docutils literal"><span class="pre">std::ostream</span></code> results in
|
||||
its numeric value being written to the stream (i.e. 1070 instead of letter ‘ю’ which
|
||||
is represented by <code class="docutils literal"><span class="pre">L'\x42e'</span></code> if we use Unicode) which is rarely what is needed.</p>
|
||||
its numeric value being written to the stream (i.e. 1070 instead of letter ‘ю’
|
||||
which is represented by <code class="docutils literal"><span class="pre">L'\x42e'</span></code> if we use Unicode) which is rarely what is
|
||||
needed.</p>
|
||||
</div>
|
||||
<div class="section" id="portability">
|
||||
<span id="id4"></span><h2>Portability<a class="headerlink" href="#portability" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The library is highly portable. Here is an incomplete list of operating systems and
|
||||
compilers where it has been tested and known to work:</p>
|
||||
<p>The library is highly portable. Here is an incomplete list of operating systems
|
||||
and compilers where it has been tested and known to work:</p>
|
||||
<ul class="simple">
|
||||
<li>64-bit (amd64) GNU/Linux with GCC 4.4.3, <a class="reference external" href="https://travis-ci.org/fmtlib/fmt">4.6.3</a>,
|
||||
4.7.2, 4.8.1 and Intel C++ Compiler (ICC) 14.0.2</li>
|
||||
<li>64-bit (amd64) GNU/Linux with GCC 4.4.3,
|
||||
<a class="reference external" href="https://travis-ci.org/fmtlib/fmt">4.6.3</a>, 4.7.2, 4.8.1, and Intel C++
|
||||
Compiler (ICC) 14.0.2</li>
|
||||
<li>32-bit (i386) GNU/Linux with GCC 4.4.3, 4.6.3</li>
|
||||
<li>Mac OS X with GCC 4.2.1 and Clang 4.2, 5.1.0</li>
|
||||
<li>64-bit Windows with Visual C++ 2010, 2013 and
|
||||
<a class="reference external" href="https://ci.appveyor.com/project/vitaut/fmt">2015</a></li>
|
||||
<li>32-bit Windows with Visual C++ 2010</li>
|
||||
</ul>
|
||||
<p>Although the library uses C++11 features when available, it also works with older
|
||||
compilers and standard library implementations. The only thing to keep in mind
|
||||
for C++98 portability:</p>
|
||||
<p>Although the library uses C++11 features when available, it also works with
|
||||
older compilers and standard library implementations. The only thing to keep in
|
||||
mind for C++98 portability:</p>
|
||||
<ul class="simple">
|
||||
<li>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.</li>
|
||||
the Format API to accept an unlimited number of arguments. With older
|
||||
compilers the maximum is 15.</li>
|
||||
<li>User-defined literals: minimum GCC 4.7, Clang 3.1 or VS2015. The suffixes
|
||||
<code class="docutils literal"><span class="pre">_format</span></code> and <code class="docutils literal"><span class="pre">_a</span></code> are functionally equivalent to the functions
|
||||
<code class="docutils literal"><span class="pre">fmt::format</span></code> and <code class="docutils literal"><span class="pre">fmt::arg</span></code>.</li>
|
||||
</ul>
|
||||
<p>The output of all formatting functions is consistent across platforms. In particular,
|
||||
formatting a floating-point infinity always gives <code class="docutils literal"><span class="pre">inf</span></code> while the output
|
||||
of <code class="docutils literal"><span class="pre">printf</span></code> is platform-dependent in this case. For example,</p>
|
||||
<p>The output of all formatting functions is consistent across platforms. In
|
||||
particular, formatting a floating-point infinity always gives <code class="docutils literal"><span class="pre">inf</span></code> while the
|
||||
output of <code class="docutils literal"><span class="pre">printf</span></code> is platform-dependent in this case. For example,</p>
|
||||
<div class="code highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">numeric_limits</span><span class="o"><</span><span class="kt">double</span><span class="o">>::</span><span class="n">infinity</span><span class="p">());</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
@@ -268,9 +292,10 @@ of <code class="docutils literal"><span class="pre">printf</span></code> is plat
|
||||
</div>
|
||||
<div class="section" id="ease-of-use">
|
||||
<span id="id7"></span><h2>Ease of Use<a class="headerlink" href="#ease-of-use" title="Permalink to this headline">¶</a></h2>
|
||||
<p>fmt has a small self-contained code base consisting of a single header file
|
||||
and a single source file and no external dependencies. A permissive BSD <a class="reference external" href="https://github.com/fmtlib/fmt#license">license</a> allows using the library both
|
||||
in open-source and commercial projects.</p>
|
||||
<p>fmt has a small self-contained code base with the core library consisting of
|
||||
a single header file and a single source file and no external dependencies.
|
||||
A permissive BSD <a class="reference external" href="https://github.com/fmtlib/fmt#license">license</a> allows
|
||||
using the library both in open-source and commercial projects.</p>
|
||||
<a class="btn btn-success" href="https://github.com/fmtlib/fmt">GitHub Repository</a>
|
||||
|
||||
<div class="section footer">
|
||||
@@ -288,7 +313,7 @@ in open-source and commercial projects.</p>
|
||||
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2012-2015, Victor Zverovich.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
|
||||
</div>
|
||||
|
||||
<script src="_static/bootstrap.min.js"></script>
|
||||
|
||||
Binary file not shown.
@@ -8,7 +8,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
|
||||
<title>Search — fmt 3.0.0 documentation</title>
|
||||
<title>Search — fmt 4.0.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@@ -17,10 +17,11 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: './',
|
||||
VERSION: '3.0.0',
|
||||
VERSION: '4.0.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
HAS_SOURCE: true,
|
||||
SOURCELINK_SUFFIX: ''
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
@@ -40,8 +41,9 @@
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();
|
||||
a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;
|
||||
a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-20116650-4', 'fmtlib.net');
|
||||
ga('send', 'pageview');
|
||||
@@ -56,7 +58,8 @@
|
||||
<div class="navbar-content">
|
||||
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -69,13 +72,17 @@
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||
aria-expanded="false">3.0.0 <span class="caret"></span></a>
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
|
||||
role="button" aria-expanded="false">4.0.0
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="http://fmtlib.net/2.0.0/">2.0.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.1.0/">1.1.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.0.0/">1.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/3.0.0">3.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/2.0.0">2.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/1.1.0">1.1.0</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -126,9 +133,11 @@
|
||||
containing fewer words won't appear in the result list.
|
||||
</p>
|
||||
|
||||
<form class="form-inline" role="search" action="#" method="get">
|
||||
<form class="form-inline" role="search" action="#"
|
||||
method="get">
|
||||
<div class="form-group">
|
||||
<input type="text" name="q" class="form-control" >
|
||||
<input type="text" name="q" class="form-control"
|
||||
>
|
||||
</div>
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
@@ -149,7 +158,7 @@
|
||||
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2012-2015, Victor Zverovich.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
|
||||
</div>
|
||||
|
||||
<script src="_static/bootstrap.min.js"></script>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -8,7 +8,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
|
||||
<title>Format String Syntax — fmt 3.0.0 documentation</title>
|
||||
<title>Format String Syntax — fmt 4.0.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@@ -17,10 +17,11 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: './',
|
||||
VERSION: '3.0.0',
|
||||
VERSION: '4.0.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
HAS_SOURCE: true,
|
||||
SOURCELINK_SUFFIX: ''
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
@@ -34,8 +35,9 @@
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();
|
||||
a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;
|
||||
a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-20116650-4', 'fmtlib.net');
|
||||
ga('send', 'pageview');
|
||||
@@ -49,7 +51,8 @@
|
||||
<div class="navbar-content">
|
||||
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -62,13 +65,17 @@
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||
aria-expanded="false">3.0.0 <span class="caret"></span></a>
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
|
||||
role="button" aria-expanded="false">4.0.0
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="http://fmtlib.net/2.0.0/">2.0.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.1.0/">1.1.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.0.0/">1.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/3.0.0">3.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/2.0.0">2.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/1.1.0">1.1.0</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -85,15 +92,18 @@
|
||||
|
||||
|
||||
|
||||
<li class="active"><a href="syntax.html">Syntax <span class="sr-only">(current)</span></a></li>
|
||||
<li class="active"><a href="syntax.html">Syntax
|
||||
<span class="sr-only">(current)</span></a></li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html" method="get">
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html"
|
||||
method="get">
|
||||
<div class="form-group">
|
||||
<input type="text" name="q" class="form-control" placeholder="Search" >
|
||||
<input type="text" name="q" class="form-control"
|
||||
placeholder="Search" >
|
||||
</div>
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
@@ -153,12 +163,10 @@ precision and so on. Each value type can define its own “formatting
|
||||
mini-language” or interpretation of the <em>format_spec</em>.</p>
|
||||
<p>Most built-in types support a common formatting mini-language, which is
|
||||
described in the next section.</p>
|
||||
<p>A <em>format_spec</em> field can also include nested replacement fields within it.
|
||||
These nested replacement fields can contain only an argument index;
|
||||
format specifications are not allowed. Formatting is performed as if the
|
||||
replacement fields within the format_spec are substituted before the
|
||||
<em>format_spec</em> string is interpreted. This allows the formatting of a value
|
||||
to be dynamically specified.</p>
|
||||
<p>A <em>format_spec</em> field can also include nested replacement fields in certain
|
||||
positions within it. These nested replacement fields can contain only an
|
||||
argument id; format specifications are not allowed. This allows the
|
||||
formatting of a value to be dynamically specified.</p>
|
||||
<p>See the <a class="reference internal" href="#formatexamples"><span class="std std-ref">Format examples</span></a> section for some examples.</p>
|
||||
<div class="section" id="format-specification-mini-language">
|
||||
<span id="formatspec"></span><h2>Format Specification Mini-Language<a class="headerlink" href="#format-specification-mini-language" title="Permalink to this headline">¶</a></h2>
|
||||
@@ -176,8 +184,8 @@ although some of the formatting options are only supported by the numeric types.
|
||||
<strong id="grammar-token-sign">sign </strong> ::= "+" | "-" | " "
|
||||
<strong id="grammar-token-width">width </strong> ::= <a class="reference internal" href="#grammar-token-integer"><code class="xref docutils literal"><span class="pre">integer</span></code></a> | "{" <a class="reference internal" href="#grammar-token-arg_id"><code class="xref docutils literal"><span class="pre">arg_id</span></code></a> "}"
|
||||
<strong id="grammar-token-precision">precision </strong> ::= <a class="reference internal" href="#grammar-token-integer"><code class="xref docutils literal"><span class="pre">integer</span></code></a> | "{" <a class="reference internal" href="#grammar-token-arg_id"><code class="xref docutils literal"><span class="pre">arg_id</span></code></a> "}"
|
||||
<strong id="grammar-token-type">type </strong> ::= <a class="reference internal" href="#grammar-token-int_type"><code class="xref docutils literal"><span class="pre">int_type</span></code></a> | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
|
||||
<strong id="grammar-token-int_type">int_type </strong> ::= "b" | "B" | "d" | "o" | "x" | "X"
|
||||
<strong id="grammar-token-type">type </strong> ::= <a class="reference internal" href="#grammar-token-int_type"><code class="xref docutils literal"><span class="pre">int_type</span></code></a> | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
|
||||
<strong id="grammar-token-int_type">int_type </strong> ::= "b" | "B" | "d" | "n" | "o" | "x" | "X"
|
||||
</pre>
|
||||
<p>The <em>fill</em> character can be any character other than ‘{‘ or ‘}’. The presence
|
||||
of a fill character is signaled by the character following it, which must be
|
||||
@@ -383,7 +391,7 @@ Boolean values are formatted using textual representation, either <code class="d
|
||||
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'a'</span></code></td>
|
||||
<td>Hexadecimal floating point format. Prints the number in
|
||||
base 16 with prefix <code class="docutils literal"><span class="pre">"0x"</span></code> and lower-case letters for
|
||||
digits above 9. Uses ‘p’ to indicate the exponent.</td>
|
||||
digits above 9. Uses <code class="docutils literal"><span class="pre">'p'</span></code> to indicate the exponent.</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><code class="docutils literal"><span class="pre">'A'</span></code></td>
|
||||
<td>Same as <code class="docutils literal"><span class="pre">'a'</span></code> except it uses upper-case letters for
|
||||
@@ -507,7 +515,7 @@ following examples.</p>
|
||||
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2012-2015, Victor Zverovich.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
|
||||
</div>
|
||||
|
||||
<script src="_static/bootstrap.min.js"></script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
|
||||
<title>Usage — fmt 3.0.0 documentation</title>
|
||||
<title>Usage — fmt 4.0.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@@ -17,10 +17,11 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: './',
|
||||
VERSION: '3.0.0',
|
||||
VERSION: '4.0.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
HAS_SOURCE: true,
|
||||
SOURCELINK_SUFFIX: ''
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
@@ -35,8 +36,9 @@
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();
|
||||
a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;
|
||||
a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-20116650-4', 'fmtlib.net');
|
||||
ga('send', 'pageview');
|
||||
@@ -50,7 +52,8 @@
|
||||
<div class="navbar-content">
|
||||
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -63,13 +66,17 @@
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||
aria-expanded="false">3.0.0 <span class="caret"></span></a>
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
|
||||
role="button" aria-expanded="false">4.0.0
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="http://fmtlib.net/2.0.0/">2.0.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.1.0/">1.1.0</a></li>
|
||||
<li><a href="http://fmtlib.net/1.0.0/">1.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/3.0.0">3.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/2.0.0">2.0.0</a></li>
|
||||
|
||||
<li><a href="http://fmtlib.net/1.1.0">1.1.0</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -78,7 +85,8 @@
|
||||
|
||||
|
||||
|
||||
<li class="active"><a href="usage.html">Usage <span class="sr-only">(current)</span></a></li>
|
||||
<li class="active"><a href="usage.html">Usage
|
||||
<span class="sr-only">(current)</span></a></li>
|
||||
|
||||
|
||||
|
||||
@@ -92,9 +100,11 @@
|
||||
</ul>
|
||||
|
||||
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html" method="get">
|
||||
<form class="navbar-form navbar-right" role="search" action="search.html"
|
||||
method="get">
|
||||
<div class="form-group">
|
||||
<input type="text" name="q" class="form-control" placeholder="Search" >
|
||||
<input type="text" name="q" class="form-control"
|
||||
placeholder="Search" >
|
||||
</div>
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
@@ -155,14 +165,38 @@ using Visual Studio or msbuild.</p>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="header-only-usage-with-cmake">
|
||||
<h2>Header-only usage with CMake<a class="headerlink" href="#header-only-usage-with-cmake" title="Permalink to this headline">¶</a></h2>
|
||||
<p>In order to add <code class="docutils literal"><span class="pre">fmtlib</span></code> into an existing <code class="docutils literal"><span class="pre">CMakeLists.txt</span></code> file, you can add the <code class="docutils literal"><span class="pre">fmt</span></code> library directory into your main project, which will enable the <code class="docutils literal"><span class="pre">fmt</span></code> library:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">add_subdirectory</span><span class="p">(</span><span class="n">fmt</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you have a project called <code class="docutils literal"><span class="pre">foo</span></code> that you would like to link against the fmt library in a header-only fashion, you can enable with with:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">target_link_libraries</span><span class="p">(</span><span class="n">foo</span> <span class="n">PRIVATE</span> <span class="n">fmt</span><span class="o">::</span><span class="n">fmt</span><span class="o">-</span><span class="n">header</span><span class="o">-</span><span class="n">only</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>And then to ensure that the <code class="docutils literal"><span class="pre">fmt</span></code> library does not always get built, you can modify the call to <code class="docutils literal"><span class="pre">add_subdirectory</span></code> to read</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">add_subdirectory</span><span class="p">(</span><span class="n">fmt</span> <span class="n">EXCLUDE_FROM_ALL</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will ensure that the <code class="docutils literal"><span class="pre">fmt</span></code> library is exluded from calls to <code class="docutils literal"><span class="pre">make</span></code>, <code class="docutils literal"><span class="pre">make</span> <span class="pre">all</span></code>, or <code class="docutils literal"><span class="pre">cmake</span> <span class="pre">--build</span> <span class="pre">.</span></code>.</p>
|
||||
</div>
|
||||
<div class="section" id="building-the-documentation">
|
||||
<h2>Building the documentation<a class="headerlink" href="#building-the-documentation" title="Permalink to this headline">¶</a></h2>
|
||||
<p>To build the documentation you need the following software installed on your
|
||||
system:</p>
|
||||
<ul class="simple">
|
||||
<li><a class="reference external" href="https://www.python.org/">Python</a> with pip and virtualenv</li>
|
||||
<li><a class="reference external" href="http://www.stack.nl/~dimitri/doxygen/">Doxygen</a></li>
|
||||
<li><a class="reference external" href="http://lesscss.org/">Less</a> with less-plugin-clean-css</li>
|
||||
<ul>
|
||||
<li><p class="first"><a class="reference external" href="https://www.python.org/">Python</a> with pip and virtualenv</p>
|
||||
</li>
|
||||
<li><p class="first"><a class="reference external" href="http://www.stack.nl/~dimitri/doxygen/">Doxygen</a></p>
|
||||
</li>
|
||||
<li><p class="first"><a class="reference external" href="http://lesscss.org/">Less</a> with <code class="docutils literal"><span class="pre">less-plugin-clean-css</span></code>.
|
||||
Ubuntu doesn’t package the <code class="docutils literal"><span class="pre">clean-css</span></code> plugin so you should use <code class="docutils literal"><span class="pre">npm</span></code>
|
||||
instead of <code class="docutils literal"><span class="pre">apt</span></code> to install both <code class="docutils literal"><span class="pre">less</span></code> and the plugin:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">sudo</span> <span class="n">npm</span> <span class="n">install</span> <span class="o">-</span><span class="n">g</span> <span class="n">less</span> <span class="n">less</span><span class="o">-</span><span class="n">plugin</span><span class="o">-</span><span class="n">clean</span><span class="o">-</span><span class="n">css</span><span class="p">.</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<p>First generate makefiles or project files using CMake as described in
|
||||
the previous section. Then compile the <code class="docutils literal"><span class="pre">doc</span></code> target/project, for example:</p>
|
||||
@@ -182,7 +216,7 @@ repository.</p>
|
||||
<div class="section" id="homebrew">
|
||||
<h2>Homebrew<a class="headerlink" href="#homebrew" title="Permalink to this headline">¶</a></h2>
|
||||
<p>fmt can be installed on OS X using <a class="reference external" href="http://brew.sh/">Homebrew</a>:</p>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">brew</span> <span class="n">install</span> <span class="n">cppformat</span>
|
||||
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">brew</span> <span class="n">install</span> <span class="n">fmt</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -197,7 +231,7 @@ repository.</p>
|
||||
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2012-2015, Victor Zverovich.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1.
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
|
||||
</div>
|
||||
|
||||
<script src="_static/bootstrap.min.js"></script>
|
||||
|
||||
+32
-29
@@ -10,9 +10,9 @@ alternative to C++ IOStreams.
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">What users say:</div>
|
||||
<div class="panel-body">
|
||||
Thanks for creating this library. It’s been a hole in C++ for a long time.
|
||||
I’ve used both boost::format and loki::SPrintf, and neither felt like the
|
||||
right answer. This does.
|
||||
Thanks for creating this library. It’s been a hole in C++ for a long
|
||||
time. I’ve used both boost::format and loki::SPrintf, and neither felt
|
||||
like the right answer. This does.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,8 +24,8 @@ Format API
|
||||
The replacement-based Format API provides a safe alternative to ``printf``,
|
||||
``sprintf`` and friends with comparable or `better performance
|
||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
||||
The `format string syntax <doc/latest/index.html#format-string-syntax>`_ is similar
|
||||
to the one used by `str.format <http://docs.python.org/2/library/stdtypes.html#str.format>`_
|
||||
The `format string syntax <syntax.html>`_ is similar to the one used by
|
||||
`str.format <http://docs.python.org/2/library/stdtypes.html#str.format>`_
|
||||
in Python:
|
||||
|
||||
.. code:: c++
|
||||
@@ -98,8 +98,8 @@ literal operators, they must be made visible with the directive
|
||||
Write API
|
||||
---------
|
||||
|
||||
The concatenation-based Write API (experimental) provides a
|
||||
`fast <http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_
|
||||
The concatenation-based Write API (experimental) provides a `fast
|
||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_
|
||||
stateless alternative to IOStreams:
|
||||
|
||||
.. code:: c++
|
||||
@@ -112,8 +112,9 @@ stateless alternative to IOStreams:
|
||||
Safety
|
||||
------
|
||||
|
||||
The library is fully type safe, automatic memory management prevents buffer overflow,
|
||||
errors in format strings are reported using exceptions. For example, the code
|
||||
The library is fully type safe, automatic memory management prevents buffer
|
||||
overflow, errors in format strings are reported using exceptions. For example,
|
||||
the code
|
||||
|
||||
.. code:: c++
|
||||
|
||||
@@ -138,19 +139,21 @@ formatted into a narrow string. You can use a wide format string instead:
|
||||
fmt::format(L"Cyrillic letter {}", L'\x42e');
|
||||
|
||||
For comparison, writing a wide character to ``std::ostream`` results in
|
||||
its numeric value being written to the stream (i.e. 1070 instead of letter 'ю' which
|
||||
is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is needed.
|
||||
its numeric value being written to the stream (i.e. 1070 instead of letter 'ю'
|
||||
which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is
|
||||
needed.
|
||||
|
||||
.. _portability:
|
||||
|
||||
Portability
|
||||
-----------
|
||||
|
||||
The library is highly portable. Here is an incomplete list of operating systems and
|
||||
compilers where it has been tested and known to work:
|
||||
The library is highly portable. Here is an incomplete list of operating systems
|
||||
and compilers where it has been tested and known to work:
|
||||
|
||||
* 64-bit (amd64) GNU/Linux with GCC 4.4.3, `4.6.3 <https://travis-ci.org/fmtlib/fmt>`_,
|
||||
4.7.2, 4.8.1 and Intel C++ Compiler (ICC) 14.0.2
|
||||
* 64-bit (amd64) GNU/Linux with GCC 4.4.3,
|
||||
`4.6.3 <https://travis-ci.org/fmtlib/fmt>`_, 4.7.2, 4.8.1, and Intel C++
|
||||
Compiler (ICC) 14.0.2
|
||||
|
||||
* 32-bit (i386) GNU/Linux with GCC 4.4.3, 4.6.3
|
||||
|
||||
@@ -161,21 +164,21 @@ compilers where it has been tested and known to work:
|
||||
|
||||
* 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. The only thing to keep in mind
|
||||
for C++98 portability:
|
||||
Although the library uses C++11 features when available, it also works with
|
||||
older 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.
|
||||
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
|
||||
* 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
|
||||
of ``printf`` is platform-dependent in this case. For example,
|
||||
The output of all formatting functions is consistent across platforms. In
|
||||
particular, formatting a floating-point infinity always gives ``inf`` while the
|
||||
output of ``printf`` is platform-dependent in this case. For example,
|
||||
|
||||
.. code::
|
||||
|
||||
@@ -188,10 +191,10 @@ always prints ``inf``.
|
||||
Ease of Use
|
||||
-----------
|
||||
|
||||
fmt has a small self-contained code base consisting of a single header file
|
||||
and a single source file and no external dependencies. A permissive BSD `license
|
||||
<https://github.com/fmtlib/fmt#license>`_ allows using the library both
|
||||
in open-source and commercial projects.
|
||||
fmt has a small self-contained code base with the core library consisting of
|
||||
a single header file and a single source file and no external dependencies.
|
||||
A permissive BSD `license <https://github.com/fmtlib/fmt#license>`_ allows
|
||||
using the library both in open-source and commercial projects.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
|
||||
@@ -49,12 +49,10 @@ mini-language" or interpretation of the *format_spec*.
|
||||
Most built-in types support a common formatting mini-language, which is
|
||||
described in the next section.
|
||||
|
||||
A *format_spec* field can also include nested replacement fields within it.
|
||||
These nested replacement fields can contain only an argument index;
|
||||
format specifications are not allowed. Formatting is performed as if the
|
||||
replacement fields within the format_spec are substituted before the
|
||||
*format_spec* string is interpreted. This allows the formatting of a value
|
||||
to be dynamically specified.
|
||||
A *format_spec* field can also include nested replacement fields in certain
|
||||
positions within it. These nested replacement fields can contain only an
|
||||
argument id; format specifications are not allowed. This allows the
|
||||
formatting of a value to be dynamically specified.
|
||||
|
||||
See the :ref:`formatexamples` section for some examples.
|
||||
|
||||
@@ -80,8 +78,8 @@ The general form of a *standard format specifier* is:
|
||||
sign: "+" | "-" | " "
|
||||
width: `integer` | "{" `arg_id` "}"
|
||||
precision: `integer` | "{" `arg_id` "}"
|
||||
type: `int_type` | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
|
||||
int_type: "b" | "B" | "d" | "o" | "x" | "X"
|
||||
type: `int_type` | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
|
||||
int_type: "b" | "B" | "d" | "n" | "o" | "x" | "X"
|
||||
|
||||
The *fill* character can be any character other than '{' or '}'. The presence
|
||||
of a fill character is signaled by the character following it, which must be
|
||||
@@ -234,7 +232,7 @@ The available presentation types for floating-point values are:
|
||||
+=========+==========================================================+
|
||||
| ``'a'`` | Hexadecimal floating point format. Prints the number in |
|
||||
| | base 16 with prefix ``"0x"`` and lower-case letters for |
|
||||
| | digits above 9. Uses 'p' to indicate the exponent. |
|
||||
| | digits above 9. Uses ``'p'`` to indicate the exponent. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'A'`` | Same as ``'a'`` except it uses upper-case letters for |
|
||||
| | the prefix, digits above 9 and to indicate the exponent. |
|
||||
|
||||
@@ -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
|
||||
|
||||
Header-only usage with CMake
|
||||
============================
|
||||
|
||||
In order to add ``fmtlib`` into an existing ``CMakeLists.txt`` file, you can add the ``fmt`` library directory into your main project, which will enable the ``fmt`` library::
|
||||
|
||||
add_subdirectory(fmt)
|
||||
|
||||
If you have a project called ``foo`` that you would like to link against the fmt library in a header-only fashion, you can enable with with::
|
||||
|
||||
target_link_libraries(foo PRIVATE fmt::fmt-header-only)
|
||||
|
||||
And then to ensure that the ``fmt`` library does not always get built, you can modify the call to ``add_subdirectory`` to read ::
|
||||
|
||||
add_subdirectory(fmt EXCLUDE_FROM_ALL)
|
||||
|
||||
This will ensure that the ``fmt`` library is exluded from calls to ``make``, ``make all``, or ``cmake --build .``.
|
||||
|
||||
Building the documentation
|
||||
==========================
|
||||
|
||||
@@ -62,7 +79,11 @@ 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
|
||||
* `Less <http://lesscss.org/>`_ with ``less-plugin-clean-css``.
|
||||
Ubuntu doesn't package the ``clean-css`` plugin so you should use ``npm``
|
||||
instead of ``apt`` to install both ``less`` and the plugin::
|
||||
|
||||
sudo npm install -g less 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::
|
||||
@@ -87,4 +108,4 @@ Homebrew
|
||||
|
||||
fmt can be installed on OS X using `Homebrew <http://brew.sh/>`_::
|
||||
|
||||
brew install cppformat
|
||||
brew install fmt
|
||||
|
||||
@@ -1,26 +1,52 @@
|
||||
# Define the fmt library, its includes and the needed defines.
|
||||
# format.cc is added to FMT_HEADERS for the header-only configuration.
|
||||
set(FMT_HEADERS format.h format.cc ostream.h ostream.cc time.h)
|
||||
# *.cc are added to FMT_HEADERS for the header-only configuration.
|
||||
set(FMT_HEADERS container.h format.h format.cc ostream.h ostream.cc printf.h
|
||||
printf.cc string.h time.h)
|
||||
if (HAVE_OPEN)
|
||||
set(FMT_HEADERS ${FMT_HEADERS} posix.h)
|
||||
set(FMT_SOURCES ${FMT_SOURCES} posix.cc)
|
||||
endif ()
|
||||
|
||||
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../ChangeLog.rst)
|
||||
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../README.rst ../ChangeLog.rst)
|
||||
add_library(fmt::fmt ALIAS fmt)
|
||||
|
||||
option(FMT_CPPFORMAT "Build cppformat library for backward compatibility." OFF)
|
||||
if (FMT_CPPFORMAT)
|
||||
message(WARNING "The cppformat library is deprecated, use fmt instead.")
|
||||
add_library(cppformat ${FMT_SOURCES} ${FMT_HEADERS})
|
||||
# Starting with cmake 3.1 the CXX_STANDARD property can be used instead.
|
||||
# Note: Don't make -std=c++11 public or interface, since it breaks projects
|
||||
# that use C++14.
|
||||
target_compile_options(fmt PRIVATE ${CPP11_FLAG})
|
||||
if (FMT_PEDANTIC)
|
||||
target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||
endif ()
|
||||
|
||||
include_directories(fmt INTERFACE
|
||||
target_include_directories(fmt PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
|
||||
set_target_properties(fmt PROPERTIES
|
||||
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR})
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
if (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(fmt -Wl,--as-needed)
|
||||
endif ()
|
||||
target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED)
|
||||
endif ()
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# additionally define a header only library when cmake is new enough
|
||||
if (CMAKE_VERSION VERSION_GREATER 3.1.0 OR CMAKE_VERSION VERSION_EQUAL 3.1.0)
|
||||
add_library(fmt-header-only INTERFACE)
|
||||
add_library(fmt::fmt-header-only ALIAS fmt-header-only)
|
||||
|
||||
target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
|
||||
|
||||
target_include_directories(fmt-header-only INTERFACE
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
endif ()
|
||||
|
||||
# Install targets.
|
||||
if (FMT_INSTALL)
|
||||
include(CMakePackageConfigHelpers)
|
||||
@@ -47,18 +73,18 @@ if (FMT_INSTALL)
|
||||
${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
|
||||
${project_config}
|
||||
INSTALL_DESTINATION ${FMT_CMAKE_DIR})
|
||||
export(TARGETS ${INSTALL_TARGETS} FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
|
||||
export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt::
|
||||
FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
|
||||
|
||||
# Install version, config and target files.
|
||||
install(
|
||||
FILES ${project_config} ${version_config}
|
||||
DESTINATION ${FMT_CMAKE_DIR})
|
||||
install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR})
|
||||
install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}
|
||||
NAMESPACE fmt::)
|
||||
|
||||
# Install the library and headers.
|
||||
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name} DESTINATION ${FMT_LIB_DIR})
|
||||
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
|
||||
DESTINATION ${FMT_LIB_DIR})
|
||||
install(FILES ${FMT_HEADERS} DESTINATION include/fmt)
|
||||
if (FMT_CPPFORMAT)
|
||||
install(TARGETS cppformat DESTINATION ${FMT_LIB_DIR})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Formatting library for C++ - standard container utilities
|
||||
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
#ifndef FMT_CONTAINER_H_
|
||||
#define FMT_CONTAINER_H_
|
||||
|
||||
#include "format.h"
|
||||
|
||||
namespace fmt {
|
||||
|
||||
namespace internal {
|
||||
|
||||
/**
|
||||
\rst
|
||||
A "buffer" that appends data to a standard container (e.g. typically a
|
||||
``std::vector`` or ``std::basic_string``).
|
||||
\endrst
|
||||
*/
|
||||
template <typename Container>
|
||||
class ContainerBuffer : public Buffer<typename Container::value_type> {
|
||||
private:
|
||||
Container& container_;
|
||||
|
||||
protected:
|
||||
virtual void grow(std::size_t size) FMT_OVERRIDE {
|
||||
container_.resize(size);
|
||||
this->ptr_ = &container_[0];
|
||||
this->capacity_ = size;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit ContainerBuffer(Container& container) : container_(container) {
|
||||
this->size_ = container_.size();
|
||||
if (this->size_ > 0) {
|
||||
this->ptr_ = &container_[0];
|
||||
this->capacity_ = this->size_;
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
\rst
|
||||
This class template provides operations for formatting and appending data
|
||||
to a standard *container* like ``std::vector`` or ``std::basic_string``.
|
||||
|
||||
**Example**::
|
||||
|
||||
void vecformat(std::vector<char>& dest, fmt::BasicCStringRef<char> format,
|
||||
fmt::ArgList args) {
|
||||
fmt::BasicContainerWriter<std::vector<char> > appender(dest);
|
||||
appender.write(format, args);
|
||||
}
|
||||
FMT_VARIADIC(void, vecformat, std::vector<char>&,
|
||||
fmt::BasicCStringRef<char>);
|
||||
\endrst
|
||||
*/
|
||||
template <class Container>
|
||||
class BasicContainerWriter
|
||||
: public BasicWriter<typename Container::value_type> {
|
||||
private:
|
||||
internal::ContainerBuffer<Container> buffer_;
|
||||
|
||||
public:
|
||||
/**
|
||||
\rst
|
||||
Constructs a :class:`fmt::BasicContainerWriter` object.
|
||||
\endrst
|
||||
*/
|
||||
explicit BasicContainerWriter(Container& dest)
|
||||
: BasicWriter<typename Container::value_type>(buffer_), buffer_(dest) {}
|
||||
};
|
||||
|
||||
} // namespace fmt
|
||||
|
||||
#endif // FMT_CONTAINER_H_
|
||||
+67
-467
@@ -41,6 +41,9 @@
|
||||
#endif
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
|
||||
# include <windows.h>
|
||||
# else
|
||||
@@ -50,8 +53,6 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
using fmt::internal::Arg;
|
||||
|
||||
#if FMT_EXCEPTIONS
|
||||
# define FMT_TRY try
|
||||
# define FMT_CATCH(x) catch (x)
|
||||
@@ -79,6 +80,11 @@ static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
|
||||
}
|
||||
|
||||
namespace fmt {
|
||||
|
||||
FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {}
|
||||
FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {}
|
||||
FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {}
|
||||
|
||||
namespace {
|
||||
|
||||
#ifndef _MSC_VER
|
||||
@@ -100,27 +106,6 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
|
||||
# define FMT_SWPRINTF swprintf
|
||||
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
||||
|
||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||
// signed and unsigned integers.
|
||||
template <bool IsSigned>
|
||||
struct IntChecker {
|
||||
template <typename T>
|
||||
static bool fits_in_int(T value) {
|
||||
unsigned max = INT_MAX;
|
||||
return value <= max;
|
||||
}
|
||||
static bool fits_in_int(bool) { return true; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IntChecker<true> {
|
||||
template <typename T>
|
||||
static bool fits_in_int(T value) {
|
||||
return value >= INT_MIN && value <= INT_MAX;
|
||||
}
|
||||
static bool fits_in_int(int) { return true; }
|
||||
};
|
||||
|
||||
const char RESET_COLOR[] = "\x1b[0m";
|
||||
|
||||
typedef void (*FormatFunc)(Writer &, int, StringRef);
|
||||
@@ -186,7 +171,8 @@ int safe_strerror(
|
||||
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
|
||||
|
||||
int run() {
|
||||
strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
|
||||
// Suppress a warning about unused strerror_r.
|
||||
strerror_r(0, FMT_NULL, "");
|
||||
return handle(strerror_r(error_code_, buffer_, buffer_size_));
|
||||
}
|
||||
};
|
||||
@@ -225,222 +211,19 @@ void report_error(FormatFunc func, int error_code,
|
||||
std::fwrite(full_message.data(), full_message.size(), 1, stderr);
|
||||
std::fputc('\n', stderr);
|
||||
}
|
||||
|
||||
// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
|
||||
class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
|
||||
public:
|
||||
template <typename T>
|
||||
bool visit_any_int(T value) { return value == 0; }
|
||||
};
|
||||
|
||||
// Checks if an argument is a valid printf width specifier and sets
|
||||
// left alignment if it is negative.
|
||||
class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
|
||||
private:
|
||||
FormatSpec &spec_;
|
||||
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
|
||||
|
||||
public:
|
||||
explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
|
||||
|
||||
void report_unhandled_arg() {
|
||||
FMT_THROW(FormatError("width is not integer"));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
unsigned visit_any_int(T value) {
|
||||
typedef typename internal::IntTraits<T>::MainType UnsignedType;
|
||||
UnsignedType width = static_cast<UnsignedType>(value);
|
||||
if (internal::is_negative(value)) {
|
||||
spec_.align_ = ALIGN_LEFT;
|
||||
width = 0 - width;
|
||||
}
|
||||
if (width > INT_MAX)
|
||||
FMT_THROW(FormatError("number is too big"));
|
||||
return static_cast<unsigned>(width);
|
||||
}
|
||||
};
|
||||
|
||||
class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> {
|
||||
public:
|
||||
void report_unhandled_arg() {
|
||||
FMT_THROW(FormatError("precision is not integer"));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int visit_any_int(T value) {
|
||||
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||
FMT_THROW(FormatError("number is too big"));
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct is_same {
|
||||
enum { value = 0 };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_same<T, T> {
|
||||
enum { value = 1 };
|
||||
};
|
||||
|
||||
// An argument visitor that converts an integer argument to T for printf,
|
||||
// if T is an integral type. If T is void, the argument is converted to
|
||||
// corresponding signed or unsigned type depending on the type specifier:
|
||||
// 'd' and 'i' - signed, other - unsigned)
|
||||
template <typename T = void>
|
||||
class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
|
||||
private:
|
||||
internal::Arg &arg_;
|
||||
wchar_t type_;
|
||||
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
|
||||
|
||||
public:
|
||||
ArgConverter(internal::Arg &arg, wchar_t type)
|
||||
: arg_(arg), type_(type) {}
|
||||
|
||||
void visit_bool(bool value) {
|
||||
if (type_ != 's')
|
||||
visit_any_int(value);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void visit_any_int(U value) {
|
||||
bool is_signed = type_ == 'd' || type_ == 'i';
|
||||
using internal::Arg;
|
||||
typedef typename internal::Conditional<
|
||||
is_same<T, void>::value, U, T>::type TargetType;
|
||||
if (sizeof(TargetType) <= sizeof(int)) {
|
||||
// Extra casts are used to silence warnings.
|
||||
if (is_signed) {
|
||||
arg_.type = Arg::INT;
|
||||
arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
|
||||
} else {
|
||||
arg_.type = Arg::UINT;
|
||||
typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;
|
||||
arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
|
||||
}
|
||||
} else {
|
||||
if (is_signed) {
|
||||
arg_.type = Arg::LONG_LONG;
|
||||
// glibc's printf doesn't sign extend arguments of smaller types:
|
||||
// std::printf("%lld", -42); // prints "4294967254"
|
||||
// but we don't have to do the same because it's a UB.
|
||||
arg_.long_long_value = static_cast<LongLong>(value);
|
||||
} else {
|
||||
arg_.type = Arg::ULONG_LONG;
|
||||
arg_.ulong_long_value =
|
||||
static_cast<typename internal::MakeUnsigned<U>::Type>(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Converts an integer argument to char for printf.
|
||||
class CharConverter : public ArgVisitor<CharConverter, void> {
|
||||
private:
|
||||
internal::Arg &arg_;
|
||||
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
|
||||
|
||||
public:
|
||||
explicit CharConverter(internal::Arg &arg) : arg_(arg) {}
|
||||
|
||||
template <typename T>
|
||||
void visit_any_int(T value) {
|
||||
arg_.type = internal::Arg::CHAR;
|
||||
arg_.int_value = static_cast<char>(value);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Char>
|
||||
class PrintfArgFormatter :
|
||||
public ArgFormatterBase<PrintfArgFormatter<Char>, Char> {
|
||||
|
||||
void write_null_pointer() {
|
||||
this->spec().type_ = 0;
|
||||
this->write("(nil)");
|
||||
}
|
||||
|
||||
typedef ArgFormatterBase<PrintfArgFormatter<Char>, Char> Base;
|
||||
|
||||
public:
|
||||
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
|
||||
: ArgFormatterBase<PrintfArgFormatter<Char>, Char>(w, s) {}
|
||||
|
||||
void visit_bool(bool value) {
|
||||
FormatSpec &fmt_spec = this->spec();
|
||||
if (fmt_spec.type_ != 's')
|
||||
return this->visit_any_int(value);
|
||||
fmt_spec.type_ = 0;
|
||||
this->write(value);
|
||||
}
|
||||
|
||||
void visit_char(int value) {
|
||||
const FormatSpec &fmt_spec = this->spec();
|
||||
BasicWriter<Char> &w = this->writer();
|
||||
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
|
||||
w.write_int(value, fmt_spec);
|
||||
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
||||
CharPtr out = CharPtr();
|
||||
if (fmt_spec.width_ > 1) {
|
||||
Char fill = ' ';
|
||||
out = w.grow_buffer(fmt_spec.width_);
|
||||
if (fmt_spec.align_ != ALIGN_LEFT) {
|
||||
std::fill_n(out, fmt_spec.width_ - 1, fill);
|
||||
out += fmt_spec.width_ - 1;
|
||||
} else {
|
||||
std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
|
||||
}
|
||||
} else {
|
||||
out = w.grow_buffer(1);
|
||||
}
|
||||
*out = static_cast<Char>(value);
|
||||
}
|
||||
|
||||
void visit_cstring(const char *value) {
|
||||
if (value)
|
||||
Base::visit_cstring(value);
|
||||
else if (this->spec().type_ == 'p')
|
||||
write_null_pointer();
|
||||
else
|
||||
this->write("(null)");
|
||||
}
|
||||
|
||||
void visit_pointer(const void *value) {
|
||||
if (value)
|
||||
return Base::visit_pointer(value);
|
||||
this->spec().type_ = 0;
|
||||
write_null_pointer();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
FMT_FUNC void fmt::SystemError::init(
|
||||
FMT_FUNC void SystemError::init(
|
||||
int err_code, CStringRef format_str, ArgList args) {
|
||||
error_code_ = err_code;
|
||||
MemoryWriter w;
|
||||
internal::format_system_error(w, err_code, format(format_str, args));
|
||||
format_system_error(w, err_code, format(format_str, args));
|
||||
std::runtime_error &base = *this;
|
||||
base = std::runtime_error(w.str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int fmt::internal::CharTraits<char>::format_float(
|
||||
int internal::CharTraits<char>::format_float(
|
||||
char *buffer, std::size_t size, const char *format,
|
||||
unsigned width, int precision, T value) {
|
||||
if (width == 0) {
|
||||
@@ -454,7 +237,7 @@ int fmt::internal::CharTraits<char>::format_float(
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int fmt::internal::CharTraits<wchar_t>::format_float(
|
||||
int internal::CharTraits<wchar_t>::format_float(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
||||
unsigned width, int precision, T value) {
|
||||
if (width == 0) {
|
||||
@@ -468,7 +251,7 @@ int fmt::internal::CharTraits<wchar_t>::format_float(
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const char fmt::internal::BasicData<T>::DIGITS[] =
|
||||
const char internal::BasicData<T>::DIGITS[] =
|
||||
"0001020304050607080910111213141516171819"
|
||||
"2021222324252627282930313233343536373839"
|
||||
"4041424344454647484950515253545556575859"
|
||||
@@ -487,40 +270,40 @@ const char fmt::internal::BasicData<T>::DIGITS[] =
|
||||
factor * 1000000000
|
||||
|
||||
template <typename T>
|
||||
const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
|
||||
const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
|
||||
0, FMT_POWERS_OF_10(1)
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
|
||||
const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
|
||||
0,
|
||||
FMT_POWERS_OF_10(1),
|
||||
FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
|
||||
FMT_POWERS_OF_10(ULongLong(1000000000)),
|
||||
// Multiply several constants instead of using a single long long constant
|
||||
// to avoid warnings about C++98 not supporting long long.
|
||||
fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
|
||||
ULongLong(1000000000) * ULongLong(1000000000) * 10
|
||||
};
|
||||
|
||||
FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
|
||||
FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
|
||||
(void)type;
|
||||
if (std::isprint(static_cast<unsigned char>(code))) {
|
||||
FMT_THROW(fmt::FormatError(
|
||||
fmt::format("unknown format code '{}' for {}", code, type)));
|
||||
FMT_THROW(FormatError(
|
||||
format("unknown format code '{}' for {}", code, type)));
|
||||
}
|
||||
FMT_THROW(fmt::FormatError(
|
||||
fmt::format("unknown format code '\\x{:02x}' for {}",
|
||||
FMT_THROW(FormatError(
|
||||
format("unknown format code '\\x{:02x}' for {}",
|
||||
static_cast<unsigned>(code), type)));
|
||||
}
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
|
||||
FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
|
||||
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);
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
|
||||
if (length == 0)
|
||||
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
|
||||
buffer_.resize(length + 1);
|
||||
@@ -531,30 +314,31 @@ FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
|
||||
buffer_[length] = 0;
|
||||
}
|
||||
|
||||
FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
|
||||
FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
|
||||
if (int error_code = convert(s)) {
|
||||
FMT_THROW(WindowsError(error_code,
|
||||
"cannot convert string from UTF-16 to UTF-8"));
|
||||
}
|
||||
}
|
||||
|
||||
FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
|
||||
FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
|
||||
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);
|
||||
int length = WideCharToMultiByte(
|
||||
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
|
||||
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, FMT_NULL, FMT_NULL);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
buffer_[length] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FMT_FUNC void fmt::WindowsError::init(
|
||||
FMT_FUNC void WindowsError::init(
|
||||
int err_code, CStringRef format_str, ArgList args) {
|
||||
error_code_ = err_code;
|
||||
MemoryWriter w;
|
||||
@@ -563,17 +347,17 @@ FMT_FUNC void fmt::WindowsError::init(
|
||||
base = std::runtime_error(w.str());
|
||||
}
|
||||
|
||||
FMT_FUNC void fmt::internal::format_windows_error(
|
||||
fmt::Writer &out, int error_code,
|
||||
fmt::StringRef message) FMT_NOEXCEPT {
|
||||
FMT_FUNC void internal::format_windows_error(
|
||||
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
|
||||
buffer.resize(INLINE_BUFFER_SIZE);
|
||||
for (;;) {
|
||||
wchar_t *system_message = &buffer[0];
|
||||
int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
system_message, static_cast<uint32_t>(buffer.size()), 0);
|
||||
int result = FormatMessageW(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL);
|
||||
if (result != 0) {
|
||||
UTF16ToUTF8 utf8_message;
|
||||
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
|
||||
@@ -592,12 +376,11 @@ FMT_FUNC void fmt::internal::format_windows_error(
|
||||
|
||||
#endif // FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC void fmt::internal::format_system_error(
|
||||
fmt::Writer &out, int error_code,
|
||||
fmt::StringRef message) FMT_NOEXCEPT {
|
||||
FMT_FUNC void format_system_error(
|
||||
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
|
||||
buffer.resize(INLINE_BUFFER_SIZE);
|
||||
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
|
||||
buffer.resize(internal::INLINE_BUFFER_SIZE);
|
||||
for (;;) {
|
||||
char *system_message = &buffer[0];
|
||||
int result = safe_strerror(error_code, system_message, buffer.size());
|
||||
@@ -614,11 +397,11 @@ FMT_FUNC void fmt::internal::format_system_error(
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
|
||||
void internal::ArgMap<Char>::init(const ArgList &args) {
|
||||
if (!map_.empty())
|
||||
return;
|
||||
typedef internal::NamedArg<Char> NamedArg;
|
||||
const NamedArg *named_arg = 0;
|
||||
const NamedArg *named_arg = FMT_NULL;
|
||||
bool use_values =
|
||||
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
|
||||
if (use_values) {
|
||||
@@ -659,18 +442,18 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
|
||||
void internal::FixedBuffer<Char>::grow(std::size_t) {
|
||||
FMT_THROW(std::runtime_error("buffer overflow"));
|
||||
}
|
||||
|
||||
FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
|
||||
FMT_FUNC internal::Arg internal::FormatterBase::do_get_arg(
|
||||
unsigned arg_index, const char *&error) {
|
||||
Arg arg = args_[arg_index];
|
||||
internal::Arg arg = args_[arg_index];
|
||||
switch (arg.type) {
|
||||
case Arg::NONE:
|
||||
case internal::Arg::NONE:
|
||||
error = "argument index out of range";
|
||||
break;
|
||||
case Arg::NAMED_ARG:
|
||||
case internal::Arg::NAMED_ARG:
|
||||
arg = *static_cast<const internal::Arg*>(arg.pointer);
|
||||
break;
|
||||
default:
|
||||
@@ -679,203 +462,31 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
|
||||
return arg;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void fmt::internal::PrintfFormatter<Char>::parse_flags(
|
||||
FormatSpec &spec, const Char *&s) {
|
||||
for (;;) {
|
||||
switch (*s++) {
|
||||
case '-':
|
||||
spec.align_ = ALIGN_LEFT;
|
||||
break;
|
||||
case '+':
|
||||
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
|
||||
break;
|
||||
case '0':
|
||||
spec.fill_ = '0';
|
||||
break;
|
||||
case ' ':
|
||||
spec.flags_ |= SIGN_FLAG;
|
||||
break;
|
||||
case '#':
|
||||
spec.flags_ |= HASH_FLAG;
|
||||
break;
|
||||
default:
|
||||
--s;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
Arg fmt::internal::PrintfFormatter<Char>::get_arg(
|
||||
const Char *s, unsigned arg_index) {
|
||||
(void)s;
|
||||
const char *error = 0;
|
||||
Arg arg = arg_index == UINT_MAX ?
|
||||
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
|
||||
if (error)
|
||||
FMT_THROW(FormatError(!*s ? "invalid format string" : error));
|
||||
return arg;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
|
||||
const Char *&s, FormatSpec &spec) {
|
||||
unsigned arg_index = UINT_MAX;
|
||||
Char c = *s;
|
||||
if (c >= '0' && c <= '9') {
|
||||
// Parse an argument index (if followed by '$') or a width possibly
|
||||
// preceded with '0' flag(s).
|
||||
unsigned value = parse_nonnegative_int(s);
|
||||
if (*s == '$') { // value is an argument index
|
||||
++s;
|
||||
arg_index = value;
|
||||
} else {
|
||||
if (c == '0')
|
||||
spec.fill_ = '0';
|
||||
if (value != 0) {
|
||||
// Nonzero value means that we parsed width and don't need to
|
||||
// parse it or flags again, so return now.
|
||||
spec.width_ = value;
|
||||
return arg_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
parse_flags(spec, s);
|
||||
// Parse width.
|
||||
if (*s >= '0' && *s <= '9') {
|
||||
spec.width_ = parse_nonnegative_int(s);
|
||||
} else if (*s == '*') {
|
||||
++s;
|
||||
spec.width_ = WidthHandler(spec).visit(get_arg(s));
|
||||
}
|
||||
return arg_index;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void fmt::internal::PrintfFormatter<Char>::format(
|
||||
BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) {
|
||||
const Char *start = format_str.c_str();
|
||||
const Char *s = start;
|
||||
while (*s) {
|
||||
Char c = *s++;
|
||||
if (c != '%') continue;
|
||||
if (*s == c) {
|
||||
write(writer, start, s);
|
||||
start = ++s;
|
||||
continue;
|
||||
}
|
||||
write(writer, start, s - 1);
|
||||
|
||||
FormatSpec spec;
|
||||
spec.align_ = ALIGN_RIGHT;
|
||||
|
||||
// Parse argument index, flags and width.
|
||||
unsigned arg_index = parse_header(s, spec);
|
||||
|
||||
// Parse precision.
|
||||
if (*s == '.') {
|
||||
++s;
|
||||
if ('0' <= *s && *s <= '9') {
|
||||
spec.precision_ = static_cast<int>(parse_nonnegative_int(s));
|
||||
} else if (*s == '*') {
|
||||
++s;
|
||||
spec.precision_ = PrecisionHandler().visit(get_arg(s));
|
||||
}
|
||||
}
|
||||
|
||||
Arg arg = get_arg(s, arg_index);
|
||||
if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
|
||||
spec.flags_ &= ~to_unsigned<int>(HASH_FLAG);
|
||||
if (spec.fill_ == '0') {
|
||||
if (arg.type <= Arg::LAST_NUMERIC_TYPE)
|
||||
spec.align_ = ALIGN_NUMERIC;
|
||||
else
|
||||
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
|
||||
}
|
||||
|
||||
// Parse length and convert the argument to the required type.
|
||||
switch (*s++) {
|
||||
case 'h':
|
||||
if (*s == 'h')
|
||||
ArgConverter<signed char>(arg, *++s).visit(arg);
|
||||
else
|
||||
ArgConverter<short>(arg, *s).visit(arg);
|
||||
break;
|
||||
case 'l':
|
||||
if (*s == 'l')
|
||||
ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
|
||||
else
|
||||
ArgConverter<long>(arg, *s).visit(arg);
|
||||
break;
|
||||
case 'j':
|
||||
ArgConverter<intmax_t>(arg, *s).visit(arg);
|
||||
break;
|
||||
case 'z':
|
||||
ArgConverter<std::size_t>(arg, *s).visit(arg);
|
||||
break;
|
||||
case 't':
|
||||
ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
|
||||
break;
|
||||
case 'L':
|
||||
// printf produces garbage when 'L' is omitted for long double, no
|
||||
// need to do the same.
|
||||
break;
|
||||
default:
|
||||
--s;
|
||||
ArgConverter<void>(arg, *s).visit(arg);
|
||||
}
|
||||
|
||||
// Parse type.
|
||||
if (!*s)
|
||||
FMT_THROW(FormatError("invalid format string"));
|
||||
spec.type_ = static_cast<char>(*s++);
|
||||
if (arg.type <= Arg::LAST_INTEGER_TYPE) {
|
||||
// Normalize type.
|
||||
switch (spec.type_) {
|
||||
case 'i': case 'u':
|
||||
spec.type_ = 'd';
|
||||
break;
|
||||
case 'c':
|
||||
// TODO: handle wchar_t
|
||||
CharConverter(arg).visit(arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
start = s;
|
||||
|
||||
// Format argument.
|
||||
internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
|
||||
}
|
||||
write(writer, start, s);
|
||||
}
|
||||
|
||||
FMT_FUNC void fmt::report_system_error(
|
||||
FMT_FUNC void report_system_error(
|
||||
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
|
||||
// 'fmt::' is for bcc32.
|
||||
fmt::report_error(internal::format_system_error, error_code, message);
|
||||
report_error(format_system_error, error_code, message);
|
||||
}
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
FMT_FUNC void fmt::report_windows_error(
|
||||
FMT_FUNC void report_windows_error(
|
||||
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
|
||||
// 'fmt::' is for bcc32.
|
||||
fmt::report_error(internal::format_windows_error, error_code, message);
|
||||
report_error(internal::format_windows_error, error_code, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
|
||||
FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
|
||||
MemoryWriter w;
|
||||
w.write(format_str, args);
|
||||
std::fwrite(w.data(), 1, w.size(), f);
|
||||
}
|
||||
|
||||
FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
|
||||
FMT_FUNC void print(CStringRef format_str, ArgList args) {
|
||||
print(stdout, format_str, args);
|
||||
}
|
||||
|
||||
FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
|
||||
FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {
|
||||
char escape[] = "\x1b[30m";
|
||||
escape[3] = static_cast<char>('0' + c);
|
||||
std::fputs(escape, stdout);
|
||||
@@ -883,53 +494,42 @@ FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
|
||||
std::fputs(RESET_COLOR, stdout);
|
||||
}
|
||||
|
||||
FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
|
||||
MemoryWriter w;
|
||||
printf(w, format, args);
|
||||
std::size_t size = w.size();
|
||||
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
|
||||
}
|
||||
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
|
||||
template struct fmt::internal::BasicData<void>;
|
||||
template struct internal::BasicData<void>;
|
||||
|
||||
// Explicit instantiations for char.
|
||||
|
||||
template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
|
||||
template void internal::FixedBuffer<char>::grow(std::size_t);
|
||||
|
||||
template void fmt::internal::ArgMap<char>::init(const fmt::ArgList &args);
|
||||
template void internal::ArgMap<char>::init(const ArgList &args);
|
||||
|
||||
template void fmt::internal::PrintfFormatter<char>::format(
|
||||
BasicWriter<char> &writer, CStringRef format);
|
||||
|
||||
template int fmt::internal::CharTraits<char>::format_float(
|
||||
template FMT_API int internal::CharTraits<char>::format_float(
|
||||
char *buffer, std::size_t size, const char *format,
|
||||
unsigned width, int precision, double value);
|
||||
|
||||
template int fmt::internal::CharTraits<char>::format_float(
|
||||
template FMT_API int internal::CharTraits<char>::format_float(
|
||||
char *buffer, std::size_t size, const char *format,
|
||||
unsigned width, int precision, long double value);
|
||||
|
||||
// Explicit instantiations for wchar_t.
|
||||
|
||||
template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
|
||||
template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
|
||||
|
||||
template void fmt::internal::ArgMap<wchar_t>::init(const fmt::ArgList &args);
|
||||
template void internal::ArgMap<wchar_t>::init(const ArgList &args);
|
||||
|
||||
template void fmt::internal::PrintfFormatter<wchar_t>::format(
|
||||
BasicWriter<wchar_t> &writer, WCStringRef format);
|
||||
|
||||
template int fmt::internal::CharTraits<wchar_t>::format_float(
|
||||
template FMT_API int internal::CharTraits<wchar_t>::format_float(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
||||
unsigned width, int precision, double value);
|
||||
|
||||
template int fmt::internal::CharTraits<wchar_t>::format_float(
|
||||
template FMT_API int internal::CharTraits<wchar_t>::format_float(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
||||
unsigned width, int precision, long double value);
|
||||
|
||||
#endif // FMT_HEADER_ONLY
|
||||
|
||||
} // namespace fmt
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
+409
-229
File diff suppressed because it is too large
Load Diff
@@ -4,34 +4,15 @@
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
#include "ostream.h"
|
||||
|
||||
namespace fmt {
|
||||
|
||||
namespace {
|
||||
// Write the content of w to os.
|
||||
void write(std::ostream &os, Writer &w) {
|
||||
namespace internal {
|
||||
FMT_FUNC void write(std::ostream &os, Writer &w) {
|
||||
const char *data = w.data();
|
||||
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
|
||||
UnsignedStreamSize size = w.size();
|
||||
@@ -49,13 +30,6 @@ void write(std::ostream &os, Writer &w) {
|
||||
FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) {
|
||||
MemoryWriter w;
|
||||
w.write(format_str, args);
|
||||
write(os, w);
|
||||
}
|
||||
|
||||
FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args) {
|
||||
MemoryWriter w;
|
||||
printf(w, format, args);
|
||||
write(os, w);
|
||||
return static_cast<int>(w.size());
|
||||
internal::write(os, w);
|
||||
}
|
||||
} // namespace fmt
|
||||
|
||||
+22
-50
@@ -4,25 +4,7 @@
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
#ifndef FMT_OSTREAM_H_
|
||||
@@ -42,28 +24,27 @@ class FormatBuf : public std::basic_streambuf<Char> {
|
||||
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
|
||||
|
||||
Buffer<Char> &buffer_;
|
||||
Char *start_;
|
||||
|
||||
public:
|
||||
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) {
|
||||
this->setp(start_, start_ + buffer_.capacity());
|
||||
}
|
||||
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer) {}
|
||||
|
||||
int_type overflow(int_type ch = traits_type::eof()) {
|
||||
if (!traits_type::eq_int_type(ch, traits_type::eof())) {
|
||||
size_t buf_size = size();
|
||||
buffer_.resize(buf_size);
|
||||
buffer_.reserve(buf_size * 2);
|
||||
protected:
|
||||
// The put-area is actually always empty. This makes the implementation
|
||||
// simpler and has the advantage that the streambuf and the buffer are always
|
||||
// in sync and sputc never writes into uninitialized memory. The obvious
|
||||
// disadvantage is that each call to sputc always results in a (virtual) call
|
||||
// to overflow. There is no disadvantage here for sputn since this always
|
||||
// results in a call to xsputn.
|
||||
|
||||
start_ = &buffer_[0];
|
||||
start_[buf_size] = traits_type::to_char_type(ch);
|
||||
this->setp(start_+ buf_size + 1, start_ + buf_size * 2);
|
||||
}
|
||||
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
|
||||
if (!traits_type::eq_int_type(ch, traits_type::eof()))
|
||||
buffer_.push_back(static_cast<Char>(ch));
|
||||
return ch;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return to_unsigned(this->pptr() - start_);
|
||||
std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
|
||||
buffer_.append(s, s + count);
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -84,19 +65,22 @@ struct ConvertToIntImpl<T, true> {
|
||||
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
|
||||
};
|
||||
};
|
||||
|
||||
// Write the content of w to os.
|
||||
FMT_API void write(std::ostream &os, Writer &w);
|
||||
} // namespace internal
|
||||
|
||||
// Formats a value.
|
||||
template <typename Char, typename ArgFormatter, typename T>
|
||||
void format(BasicFormatter<Char, ArgFormatter> &f,
|
||||
const Char *&format_str, const T &value) {
|
||||
template <typename Char, typename ArgFormatter_, typename T>
|
||||
void format_arg(BasicFormatter<Char, ArgFormatter_> &f,
|
||||
const Char *&format_str, const T &value) {
|
||||
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
|
||||
|
||||
internal::FormatBuf<Char> format_buf(buffer);
|
||||
std::basic_ostream<Char> output(&format_buf);
|
||||
output << value;
|
||||
|
||||
BasicStringRef<Char> str(&buffer[0], format_buf.size());
|
||||
BasicStringRef<Char> str(&buffer[0], buffer.size());
|
||||
typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
|
||||
format_str = f.format(format_str, MakeArg(str));
|
||||
}
|
||||
@@ -112,18 +96,6 @@ void format(BasicFormatter<Char, ArgFormatter> &f,
|
||||
*/
|
||||
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
|
||||
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the stream *os*.
|
||||
|
||||
**Example**::
|
||||
|
||||
fprintf(cerr, "Don't %s!", "panic");
|
||||
\endrst
|
||||
*/
|
||||
FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args);
|
||||
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
|
||||
} // namespace fmt
|
||||
|
||||
#ifdef FMT_HEADER_ONLY
|
||||
|
||||
+21
-36
@@ -1,28 +1,10 @@
|
||||
/*
|
||||
A C++ interface to POSIX functions.
|
||||
|
||||
Copyright (c) 2014 - 2016, Victor Zverovich
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
// Disable bogus MSVC warnings.
|
||||
@@ -39,6 +21,9 @@
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
|
||||
@@ -90,16 +75,16 @@ fmt::BufferedFile::BufferedFile(
|
||||
fmt::CStringRef filename, fmt::CStringRef mode) {
|
||||
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
|
||||
if (!file_)
|
||||
throw SystemError(errno, "cannot open file {}", filename);
|
||||
FMT_THROW(SystemError(errno, "cannot open file {}", filename));
|
||||
}
|
||||
|
||||
void fmt::BufferedFile::close() {
|
||||
if (!file_)
|
||||
return;
|
||||
int result = FMT_SYSTEM(fclose(file_));
|
||||
file_ = 0;
|
||||
file_ = FMT_NULL;
|
||||
if (result != 0)
|
||||
throw SystemError(errno, "cannot close file");
|
||||
FMT_THROW(SystemError(errno, "cannot close file"));
|
||||
}
|
||||
|
||||
// A macro used to prevent expansion of fileno on broken versions of MinGW.
|
||||
@@ -108,7 +93,7 @@ void fmt::BufferedFile::close() {
|
||||
int fmt::BufferedFile::fileno() const {
|
||||
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
|
||||
if (fd == -1)
|
||||
throw SystemError(errno, "cannot get file descriptor");
|
||||
FMT_THROW(SystemError(errno, "cannot get file descriptor"));
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -121,7 +106,7 @@ fmt::File::File(fmt::CStringRef path, int oflag) {
|
||||
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
|
||||
#endif
|
||||
if (fd_ == -1)
|
||||
throw SystemError(errno, "cannot open file {}", path);
|
||||
FMT_THROW(SystemError(errno, "cannot open file {}", path));
|
||||
}
|
||||
|
||||
fmt::File::~File() FMT_NOEXCEPT {
|
||||
@@ -139,7 +124,7 @@ void fmt::File::close() {
|
||||
int result = FMT_POSIX_CALL(close(fd_));
|
||||
fd_ = -1;
|
||||
if (result != 0)
|
||||
throw SystemError(errno, "cannot close file");
|
||||
FMT_THROW(SystemError(errno, "cannot close file"));
|
||||
}
|
||||
|
||||
fmt::LongLong fmt::File::size() const {
|
||||
@@ -153,7 +138,7 @@ fmt::LongLong fmt::File::size() const {
|
||||
if (size_lower == INVALID_FILE_SIZE) {
|
||||
DWORD error = GetLastError();
|
||||
if (error != NO_ERROR)
|
||||
throw WindowsError(GetLastError(), "cannot get file size");
|
||||
FMT_THROW(WindowsError(GetLastError(), "cannot get file size"));
|
||||
}
|
||||
fmt::ULongLong long_size = size_upper;
|
||||
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
|
||||
@@ -161,7 +146,7 @@ fmt::LongLong fmt::File::size() const {
|
||||
typedef struct stat Stat;
|
||||
Stat file_stat = Stat();
|
||||
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
|
||||
throw SystemError(errno, "cannot get file attributes");
|
||||
FMT_THROW(SystemError(errno, "cannot get file attributes"));
|
||||
FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
|
||||
"return type of File::size is not large enough");
|
||||
return file_stat.st_size;
|
||||
@@ -172,7 +157,7 @@ std::size_t fmt::File::read(void *buffer, std::size_t count) {
|
||||
RWResult result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
|
||||
if (result < 0)
|
||||
throw SystemError(errno, "cannot read from file");
|
||||
FMT_THROW(SystemError(errno, "cannot read from file"));
|
||||
return internal::to_unsigned(result);
|
||||
}
|
||||
|
||||
@@ -180,7 +165,7 @@ std::size_t fmt::File::write(const void *buffer, std::size_t count) {
|
||||
RWResult result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
|
||||
if (result < 0)
|
||||
throw SystemError(errno, "cannot write to file");
|
||||
FMT_THROW(SystemError(errno, "cannot write to file"));
|
||||
return internal::to_unsigned(result);
|
||||
}
|
||||
|
||||
@@ -189,7 +174,7 @@ fmt::File fmt::File::dup(int fd) {
|
||||
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
|
||||
int new_fd = FMT_POSIX_CALL(dup(fd));
|
||||
if (new_fd == -1)
|
||||
throw SystemError(errno, "cannot duplicate file descriptor {}", fd);
|
||||
FMT_THROW(SystemError(errno, "cannot duplicate file descriptor {}", fd));
|
||||
return File(new_fd);
|
||||
}
|
||||
|
||||
@@ -197,8 +182,8 @@ void fmt::File::dup2(int fd) {
|
||||
int result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||
if (result == -1) {
|
||||
throw SystemError(errno,
|
||||
"cannot duplicate file descriptor {} to {}", fd_, fd);
|
||||
FMT_THROW(SystemError(errno,
|
||||
"cannot duplicate file descriptor {} to {}", fd_, fd));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +210,7 @@ void fmt::File::pipe(File &read_end, File &write_end) {
|
||||
int result = FMT_POSIX_CALL(pipe(fds));
|
||||
#endif
|
||||
if (result != 0)
|
||||
throw SystemError(errno, "cannot create pipe");
|
||||
FMT_THROW(SystemError(errno, "cannot create pipe"));
|
||||
// The following assignments don't throw because read_fd and write_fd
|
||||
// are closed.
|
||||
read_end = File(fds[0]);
|
||||
@@ -236,7 +221,7 @@ fmt::BufferedFile fmt::File::fdopen(const char *mode) {
|
||||
// Don't retry as fdopen doesn't return EINTR.
|
||||
FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
||||
if (!f)
|
||||
throw SystemError(errno, "cannot associate stream with file descriptor");
|
||||
FMT_THROW(SystemError(errno, "cannot associate stream with file descriptor"));
|
||||
BufferedFile file(f);
|
||||
fd_ = -1;
|
||||
return file;
|
||||
@@ -250,7 +235,7 @@ long fmt::getpagesize() {
|
||||
#else
|
||||
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
|
||||
if (size < 0)
|
||||
throw SystemError(errno, "cannot get memory page size");
|
||||
FMT_THROW(SystemError(errno, "cannot get memory page size"));
|
||||
return size;
|
||||
#endif
|
||||
}
|
||||
|
||||
+30
-66
@@ -1,34 +1,16 @@
|
||||
/*
|
||||
A C++ interface to POSIX functions.
|
||||
|
||||
Copyright (c) 2014 - 2016, Victor Zverovich
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
#ifndef FMT_POSIX_H_
|
||||
#define FMT_POSIX_H_
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
|
||||
# undef __STRICT_ANSI__
|
||||
#endif
|
||||
@@ -41,7 +23,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
|
||||
#endif
|
||||
|
||||
@@ -69,25 +51,6 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if FMT_GCC_VERSION >= 407
|
||||
# define FMT_UNUSED __attribute__((unused))
|
||||
#else
|
||||
# define FMT_UNUSED
|
||||
#endif
|
||||
|
||||
#ifndef FMT_USE_STATIC_ASSERT
|
||||
# define FMT_USE_STATIC_ASSERT 0
|
||||
#endif
|
||||
|
||||
#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \
|
||||
(FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600
|
||||
# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
|
||||
#else
|
||||
# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
|
||||
# define FMT_STATIC_ASSERT(cond, message) \
|
||||
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
|
||||
#endif
|
||||
|
||||
// Retries the expression while it evaluates to error_result and errno
|
||||
// equals to EINTR.
|
||||
#ifndef _WIN32
|
||||
@@ -125,10 +88,10 @@ class BufferedFile {
|
||||
|
||||
public:
|
||||
// Constructs a BufferedFile object which doesn't represent any file.
|
||||
BufferedFile() FMT_NOEXCEPT : file_(0) {}
|
||||
BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
~BufferedFile() FMT_NOEXCEPT;
|
||||
FMT_API ~BufferedFile() FMT_NOEXCEPT;
|
||||
|
||||
#if !FMT_USE_RVALUE_REFERENCES
|
||||
// Emulate a move constructor and a move assignment operator if rvalue
|
||||
@@ -147,7 +110,7 @@ public:
|
||||
|
||||
// A "move constructor" for moving from an lvalue.
|
||||
BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
|
||||
f.file_ = 0;
|
||||
f.file_ = FMT_NULL;
|
||||
}
|
||||
|
||||
// A "move assignment operator" for moving from a temporary.
|
||||
@@ -161,7 +124,7 @@ public:
|
||||
BufferedFile &operator=(BufferedFile &other) {
|
||||
close();
|
||||
file_ = other.file_;
|
||||
other.file_ = 0;
|
||||
other.file_ = FMT_NULL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -169,7 +132,7 @@ public:
|
||||
// BufferedFile file = BufferedFile(...);
|
||||
operator Proxy() FMT_NOEXCEPT {
|
||||
Proxy p = {file_};
|
||||
file_ = 0;
|
||||
file_ = FMT_NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -179,29 +142,29 @@ public:
|
||||
|
||||
public:
|
||||
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) {
|
||||
other.file_ = 0;
|
||||
other.file_ = FMT_NULL;
|
||||
}
|
||||
|
||||
BufferedFile& operator=(BufferedFile &&other) {
|
||||
close();
|
||||
file_ = other.file_;
|
||||
other.file_ = 0;
|
||||
other.file_ = FMT_NULL;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Opens a file.
|
||||
BufferedFile(CStringRef filename, CStringRef mode);
|
||||
FMT_API BufferedFile(CStringRef filename, CStringRef mode);
|
||||
|
||||
// Closes the file.
|
||||
void close();
|
||||
FMT_API void close();
|
||||
|
||||
// Returns the pointer to a FILE object representing this file.
|
||||
FILE *get() const FMT_NOEXCEPT { return file_; }
|
||||
|
||||
// We place parentheses around fileno to workaround a bug in some versions
|
||||
// of MinGW that define fileno as a macro.
|
||||
int (fileno)() const;
|
||||
FMT_API int (fileno)() const;
|
||||
|
||||
void print(CStringRef format_str, const ArgList &args) {
|
||||
fmt::print(file_, format_str, args);
|
||||
@@ -234,7 +197,7 @@ class File {
|
||||
File() FMT_NOEXCEPT : fd_(-1) {}
|
||||
|
||||
// Opens a file and constructs a File object representing this file.
|
||||
File(CStringRef path, int oflag);
|
||||
FMT_API File(CStringRef path, int oflag);
|
||||
|
||||
#if !FMT_USE_RVALUE_REFERENCES
|
||||
// Emulate a move constructor and a move assignment operator if rvalue
|
||||
@@ -297,49 +260,50 @@ class File {
|
||||
#endif
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
~File() FMT_NOEXCEPT;
|
||||
FMT_API ~File() FMT_NOEXCEPT;
|
||||
|
||||
// Returns the file descriptor.
|
||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
||||
|
||||
// Closes the file.
|
||||
void close();
|
||||
FMT_API void close();
|
||||
|
||||
// Returns the file size. The size has signed type for consistency with
|
||||
// stat::st_size.
|
||||
LongLong size() const;
|
||||
FMT_API LongLong size() const;
|
||||
|
||||
// Attempts to read count bytes from the file into the specified buffer.
|
||||
std::size_t read(void *buffer, std::size_t count);
|
||||
FMT_API std::size_t read(void *buffer, std::size_t count);
|
||||
|
||||
// Attempts to write count bytes from the specified buffer to the file.
|
||||
std::size_t write(const void *buffer, std::size_t count);
|
||||
FMT_API std::size_t write(const void *buffer, std::size_t count);
|
||||
|
||||
// Duplicates a file descriptor with the dup function and returns
|
||||
// the duplicate as a file object.
|
||||
static File dup(int fd);
|
||||
FMT_API static File dup(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd);
|
||||
FMT_API void dup2(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
|
||||
FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
|
||||
|
||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||
// and writing respectively.
|
||||
static void pipe(File &read_end, File &write_end);
|
||||
FMT_API static void pipe(File &read_end, File &write_end);
|
||||
|
||||
// Creates a BufferedFile object associated with this file and detaches
|
||||
// this File object from the file.
|
||||
BufferedFile fdopen(const char *mode);
|
||||
FMT_API BufferedFile fdopen(const char *mode);
|
||||
};
|
||||
|
||||
// Returns the memory page size.
|
||||
long getpagesize();
|
||||
|
||||
#if defined(LC_NUMERIC_MASK) || defined(_MSC_VER)
|
||||
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
|
||||
!defined(__ANDROID__) && !defined(__CYGWIN__)
|
||||
# define FMT_LOCALE
|
||||
#endif
|
||||
|
||||
@@ -372,9 +336,9 @@ class Locale {
|
||||
public:
|
||||
typedef locale_t Type;
|
||||
|
||||
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) {
|
||||
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
|
||||
if (!locale_)
|
||||
throw fmt::SystemError(errno, "cannot create locale");
|
||||
FMT_THROW(fmt::SystemError(errno, "cannot create locale"));
|
||||
}
|
||||
~Locale() { freelocale(locale_); }
|
||||
|
||||
@@ -383,7 +347,7 @@ class Locale {
|
||||
// Converts string to floating-point number and advances str past the end
|
||||
// of the parsed input.
|
||||
double strtod(const char *&str) const {
|
||||
char *end = 0;
|
||||
char *end = FMT_NULL;
|
||||
double result = strtod_l(str, &end, locale_);
|
||||
str = end;
|
||||
return result;
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Formatting library for C++
|
||||
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
#include "format.h"
|
||||
#include "printf.h"
|
||||
|
||||
namespace fmt {
|
||||
|
||||
template <typename Char>
|
||||
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args);
|
||||
|
||||
FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) {
|
||||
MemoryWriter w;
|
||||
printf(w, format, args);
|
||||
std::size_t size = w.size();
|
||||
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
|
||||
}
|
||||
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
|
||||
template void PrintfFormatter<char>::format(CStringRef format);
|
||||
template void PrintfFormatter<wchar_t>::format(WCStringRef format);
|
||||
|
||||
#endif // FMT_HEADER_ONLY
|
||||
|
||||
} // namespace fmt
|
||||
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
Formatting library for C++
|
||||
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
#ifndef FMT_PRINTF_H_
|
||||
#define FMT_PRINTF_H_
|
||||
|
||||
#include <algorithm> // std::fill_n
|
||||
#include <limits> // std::numeric_limits
|
||||
|
||||
#include "ostream.h"
|
||||
|
||||
namespace fmt {
|
||||
namespace internal {
|
||||
|
||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||
// signed and unsigned integers.
|
||||
template <bool IsSigned>
|
||||
struct IntChecker {
|
||||
template <typename T>
|
||||
static bool fits_in_int(T value) {
|
||||
unsigned max = std::numeric_limits<int>::max();
|
||||
return value <= max;
|
||||
}
|
||||
static bool fits_in_int(bool) { return true; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IntChecker<true> {
|
||||
template <typename T>
|
||||
static bool fits_in_int(T value) {
|
||||
return value >= std::numeric_limits<int>::min() &&
|
||||
value <= std::numeric_limits<int>::max();
|
||||
}
|
||||
static bool fits_in_int(int) { return true; }
|
||||
};
|
||||
|
||||
class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> {
|
||||
public:
|
||||
void report_unhandled_arg() {
|
||||
FMT_THROW(FormatError("precision is not integer"));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int visit_any_int(T value) {
|
||||
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||
FMT_THROW(FormatError("number is too big"));
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
};
|
||||
|
||||
// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
|
||||
class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
|
||||
public:
|
||||
template <typename T>
|
||||
bool visit_any_int(T value) { return value == 0; }
|
||||
};
|
||||
|
||||
// returns the default type for format specific "%s"
|
||||
class DefaultType : public ArgVisitor<DefaultType, char> {
|
||||
public:
|
||||
char visit_char(int) { return 'c'; }
|
||||
|
||||
char visit_bool(bool) { return 's'; }
|
||||
|
||||
char visit_pointer(const void *) { return 'p'; }
|
||||
|
||||
template <typename T>
|
||||
char visit_any_int(T) { return 'd'; }
|
||||
|
||||
template <typename T>
|
||||
char visit_any_double(T) { return 'g'; }
|
||||
|
||||
char visit_unhandled_arg() { return 's'; }
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct is_same {
|
||||
enum { value = 0 };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_same<T, T> {
|
||||
enum { value = 1 };
|
||||
};
|
||||
|
||||
// An argument visitor that converts an integer argument to T for printf,
|
||||
// if T is an integral type. If T is void, the argument is converted to
|
||||
// corresponding signed or unsigned type depending on the type specifier:
|
||||
// 'd' and 'i' - signed, other - unsigned)
|
||||
template <typename T = void>
|
||||
class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
|
||||
private:
|
||||
internal::Arg &arg_;
|
||||
wchar_t type_;
|
||||
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
|
||||
|
||||
public:
|
||||
ArgConverter(internal::Arg &arg, wchar_t type)
|
||||
: arg_(arg), type_(type) {}
|
||||
|
||||
void visit_bool(bool value) {
|
||||
if (type_ != 's')
|
||||
visit_any_int(value);
|
||||
}
|
||||
|
||||
void visit_char(char value) {
|
||||
if (type_ != 's')
|
||||
visit_any_int(value);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void visit_any_int(U value) {
|
||||
bool is_signed = type_ == 'd' || type_ == 'i';
|
||||
if (type_ == 's') {
|
||||
is_signed = std::numeric_limits<U>::is_signed;
|
||||
}
|
||||
|
||||
using internal::Arg;
|
||||
typedef typename internal::Conditional<
|
||||
is_same<T, void>::value, U, T>::type TargetType;
|
||||
if (sizeof(TargetType) <= sizeof(int)) {
|
||||
// Extra casts are used to silence warnings.
|
||||
if (is_signed) {
|
||||
arg_.type = Arg::INT;
|
||||
arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
|
||||
} else {
|
||||
arg_.type = Arg::UINT;
|
||||
typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;
|
||||
arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
|
||||
}
|
||||
} else {
|
||||
if (is_signed) {
|
||||
arg_.type = Arg::LONG_LONG;
|
||||
// glibc's printf doesn't sign extend arguments of smaller types:
|
||||
// std::printf("%lld", -42); // prints "4294967254"
|
||||
// but we don't have to do the same because it's a UB.
|
||||
arg_.long_long_value = static_cast<LongLong>(value);
|
||||
} else {
|
||||
arg_.type = Arg::ULONG_LONG;
|
||||
arg_.ulong_long_value =
|
||||
static_cast<typename internal::MakeUnsigned<U>::Type>(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Converts an integer argument to char for printf.
|
||||
class CharConverter : public ArgVisitor<CharConverter, void> {
|
||||
private:
|
||||
internal::Arg &arg_;
|
||||
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
|
||||
|
||||
public:
|
||||
explicit CharConverter(internal::Arg &arg) : arg_(arg) {}
|
||||
|
||||
template <typename T>
|
||||
void visit_any_int(T value) {
|
||||
arg_.type = internal::Arg::CHAR;
|
||||
arg_.int_value = static_cast<char>(value);
|
||||
}
|
||||
};
|
||||
|
||||
// Checks if an argument is a valid printf width specifier and sets
|
||||
// left alignment if it is negative.
|
||||
class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
|
||||
private:
|
||||
FormatSpec &spec_;
|
||||
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
|
||||
|
||||
public:
|
||||
explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
|
||||
|
||||
void report_unhandled_arg() {
|
||||
FMT_THROW(FormatError("width is not integer"));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
unsigned visit_any_int(T value) {
|
||||
typedef typename internal::IntTraits<T>::MainType UnsignedType;
|
||||
UnsignedType width = static_cast<UnsignedType>(value);
|
||||
if (internal::is_negative(value)) {
|
||||
spec_.align_ = ALIGN_LEFT;
|
||||
width = 0 - width;
|
||||
}
|
||||
unsigned int_max = std::numeric_limits<int>::max();
|
||||
if (width > int_max)
|
||||
FMT_THROW(FormatError("number is too big"));
|
||||
return static_cast<unsigned>(width);
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
\rst
|
||||
A ``printf`` argument formatter based on the `curiously recurring template
|
||||
pattern <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.
|
||||
|
||||
To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some
|
||||
or all of the visit methods with the same signatures as the methods in
|
||||
`~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`.
|
||||
Pass the subclass as the *Impl* template parameter. When a formatting
|
||||
function processes an argument, it will dispatch to a visit method
|
||||
specific to the argument type. For example, if the argument type is
|
||||
``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass
|
||||
will be called. If the subclass doesn't contain a method with this signature,
|
||||
then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its
|
||||
superclass will be called.
|
||||
\endrst
|
||||
*/
|
||||
template <typename Impl, typename Char, typename Spec>
|
||||
class BasicPrintfArgFormatter :
|
||||
public internal::ArgFormatterBase<Impl, Char, Spec> {
|
||||
private:
|
||||
void write_null_pointer() {
|
||||
this->spec().type_ = 0;
|
||||
this->write("(nil)");
|
||||
}
|
||||
|
||||
typedef internal::ArgFormatterBase<Impl, Char, Spec> Base;
|
||||
|
||||
public:
|
||||
/**
|
||||
\rst
|
||||
Constructs an argument formatter object.
|
||||
*writer* is a reference to the output writer and *spec* contains format
|
||||
specifier information for standard argument types.
|
||||
\endrst
|
||||
*/
|
||||
BasicPrintfArgFormatter(BasicWriter<Char> &w, Spec &s)
|
||||
: internal::ArgFormatterBase<Impl, Char, Spec>(w, s) {}
|
||||
|
||||
/** Formats an argument of type ``bool``. */
|
||||
void visit_bool(bool value) {
|
||||
Spec &fmt_spec = this->spec();
|
||||
if (fmt_spec.type_ != 's')
|
||||
return this->visit_any_int(value);
|
||||
fmt_spec.type_ = 0;
|
||||
this->write(value);
|
||||
}
|
||||
|
||||
/** Formats a character. */
|
||||
void visit_char(int value) {
|
||||
const Spec &fmt_spec = this->spec();
|
||||
BasicWriter<Char> &w = this->writer();
|
||||
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
|
||||
w.write_int(value, fmt_spec);
|
||||
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
||||
CharPtr out = CharPtr();
|
||||
if (fmt_spec.width_ > 1) {
|
||||
Char fill = ' ';
|
||||
out = w.grow_buffer(fmt_spec.width_);
|
||||
if (fmt_spec.align_ != ALIGN_LEFT) {
|
||||
std::fill_n(out, fmt_spec.width_ - 1, fill);
|
||||
out += fmt_spec.width_ - 1;
|
||||
} else {
|
||||
std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
|
||||
}
|
||||
} else {
|
||||
out = w.grow_buffer(1);
|
||||
}
|
||||
*out = static_cast<Char>(value);
|
||||
}
|
||||
|
||||
/** Formats a null-terminated C string. */
|
||||
void visit_cstring(const char *value) {
|
||||
if (value)
|
||||
Base::visit_cstring(value);
|
||||
else if (this->spec().type_ == 'p')
|
||||
write_null_pointer();
|
||||
else
|
||||
this->write("(null)");
|
||||
}
|
||||
|
||||
/** Formats a pointer. */
|
||||
void visit_pointer(const void *value) {
|
||||
if (value)
|
||||
return Base::visit_pointer(value);
|
||||
this->spec().type_ = 0;
|
||||
write_null_pointer();
|
||||
}
|
||||
|
||||
/** Formats an argument of a custom (user-defined) type. */
|
||||
void visit_custom(internal::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);
|
||||
}
|
||||
};
|
||||
|
||||
/** The default printf argument formatter. */
|
||||
template <typename Char>
|
||||
class PrintfArgFormatter :
|
||||
public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec> {
|
||||
public:
|
||||
/** Constructs an argument formatter object. */
|
||||
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
|
||||
: BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>(w, s) {}
|
||||
};
|
||||
|
||||
/** This template formats data and writes the output to a writer. */
|
||||
template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> >
|
||||
class PrintfFormatter : private internal::FormatterBase {
|
||||
private:
|
||||
BasicWriter<Char> &writer_;
|
||||
|
||||
void parse_flags(FormatSpec &spec, const Char *&s);
|
||||
|
||||
// Returns the argument with specified index or, if arg_index is equal
|
||||
// to the maximum unsigned value, the next argument.
|
||||
internal::Arg get_arg(
|
||||
const Char *s,
|
||||
unsigned arg_index = (std::numeric_limits<unsigned>::max)());
|
||||
|
||||
// Parses argument index, flags and width and returns the argument index.
|
||||
unsigned parse_header(const Char *&s, FormatSpec &spec);
|
||||
|
||||
public:
|
||||
/**
|
||||
\rst
|
||||
Constructs a ``PrintfFormatter`` object. References to the arguments and
|
||||
the writer are stored in the formatter object so make sure they have
|
||||
appropriate lifetimes.
|
||||
\endrst
|
||||
*/
|
||||
explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w)
|
||||
: FormatterBase(al), writer_(w) {}
|
||||
|
||||
/** Formats stored arguments and writes the output to the writer. */
|
||||
void format(BasicCStringRef<Char> format_str);
|
||||
};
|
||||
|
||||
template <typename Char, typename AF>
|
||||
void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s) {
|
||||
for (;;) {
|
||||
switch (*s++) {
|
||||
case '-':
|
||||
spec.align_ = ALIGN_LEFT;
|
||||
break;
|
||||
case '+':
|
||||
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
|
||||
break;
|
||||
case '0':
|
||||
spec.fill_ = '0';
|
||||
break;
|
||||
case ' ':
|
||||
spec.flags_ |= SIGN_FLAG;
|
||||
break;
|
||||
case '#':
|
||||
spec.flags_ |= HASH_FLAG;
|
||||
break;
|
||||
default:
|
||||
--s;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char, typename AF>
|
||||
internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
|
||||
unsigned arg_index) {
|
||||
(void)s;
|
||||
const char *error = FMT_NULL;
|
||||
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
|
||||
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
|
||||
if (error)
|
||||
FMT_THROW(FormatError(!*s ? "invalid format string" : error));
|
||||
return arg;
|
||||
}
|
||||
|
||||
template <typename Char, typename AF>
|
||||
unsigned PrintfFormatter<Char, AF>::parse_header(
|
||||
const Char *&s, FormatSpec &spec) {
|
||||
unsigned arg_index = std::numeric_limits<unsigned>::max();
|
||||
Char c = *s;
|
||||
if (c >= '0' && c <= '9') {
|
||||
// Parse an argument index (if followed by '$') or a width possibly
|
||||
// preceded with '0' flag(s).
|
||||
unsigned value = internal::parse_nonnegative_int(s);
|
||||
if (*s == '$') { // value is an argument index
|
||||
++s;
|
||||
arg_index = value;
|
||||
} else {
|
||||
if (c == '0')
|
||||
spec.fill_ = '0';
|
||||
if (value != 0) {
|
||||
// Nonzero value means that we parsed width and don't need to
|
||||
// parse it or flags again, so return now.
|
||||
spec.width_ = value;
|
||||
return arg_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
parse_flags(spec, s);
|
||||
// Parse width.
|
||||
if (*s >= '0' && *s <= '9') {
|
||||
spec.width_ = internal::parse_nonnegative_int(s);
|
||||
} else if (*s == '*') {
|
||||
++s;
|
||||
spec.width_ = internal::WidthHandler(spec).visit(get_arg(s));
|
||||
}
|
||||
return arg_index;
|
||||
}
|
||||
|
||||
template <typename Char, typename AF>
|
||||
void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) {
|
||||
const Char *start = format_str.c_str();
|
||||
const Char *s = start;
|
||||
while (*s) {
|
||||
Char c = *s++;
|
||||
if (c != '%') continue;
|
||||
if (*s == c) {
|
||||
write(writer_, start, s);
|
||||
start = ++s;
|
||||
continue;
|
||||
}
|
||||
write(writer_, start, s - 1);
|
||||
|
||||
FormatSpec spec;
|
||||
spec.align_ = ALIGN_RIGHT;
|
||||
|
||||
// Parse argument index, flags and width.
|
||||
unsigned arg_index = parse_header(s, spec);
|
||||
|
||||
// Parse precision.
|
||||
if (*s == '.') {
|
||||
++s;
|
||||
if ('0' <= *s && *s <= '9') {
|
||||
spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s));
|
||||
} else if (*s == '*') {
|
||||
++s;
|
||||
spec.precision_ = internal::PrecisionHandler().visit(get_arg(s));
|
||||
} else {
|
||||
spec.precision_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
using internal::Arg;
|
||||
Arg arg = get_arg(s, arg_index);
|
||||
if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg))
|
||||
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
|
||||
if (spec.fill_ == '0') {
|
||||
if (arg.type <= Arg::LAST_NUMERIC_TYPE)
|
||||
spec.align_ = ALIGN_NUMERIC;
|
||||
else
|
||||
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
|
||||
}
|
||||
|
||||
// Parse length and convert the argument to the required type.
|
||||
using internal::ArgConverter;
|
||||
switch (*s++) {
|
||||
case 'h':
|
||||
if (*s == 'h')
|
||||
ArgConverter<signed char>(arg, *++s).visit(arg);
|
||||
else
|
||||
ArgConverter<short>(arg, *s).visit(arg);
|
||||
break;
|
||||
case 'l':
|
||||
if (*s == 'l')
|
||||
ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
|
||||
else
|
||||
ArgConverter<long>(arg, *s).visit(arg);
|
||||
break;
|
||||
case 'j':
|
||||
ArgConverter<intmax_t>(arg, *s).visit(arg);
|
||||
break;
|
||||
case 'z':
|
||||
ArgConverter<std::size_t>(arg, *s).visit(arg);
|
||||
break;
|
||||
case 't':
|
||||
ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
|
||||
break;
|
||||
case 'L':
|
||||
// printf produces garbage when 'L' is omitted for long double, no
|
||||
// need to do the same.
|
||||
break;
|
||||
default:
|
||||
--s;
|
||||
ArgConverter<void>(arg, *s).visit(arg);
|
||||
}
|
||||
|
||||
// Parse type.
|
||||
if (!*s)
|
||||
FMT_THROW(FormatError("invalid format string"));
|
||||
spec.type_ = static_cast<char>(*s++);
|
||||
|
||||
if (spec.type_ == 's') {
|
||||
// set the format type to the default if 's' is specified
|
||||
spec.type_ = internal::DefaultType().visit(arg);
|
||||
}
|
||||
|
||||
if (arg.type <= Arg::LAST_INTEGER_TYPE) {
|
||||
// Normalize type.
|
||||
switch (spec.type_) {
|
||||
case 'i': case 'u':
|
||||
spec.type_ = 'd';
|
||||
break;
|
||||
case 'c':
|
||||
// TODO: handle wchar_t
|
||||
internal::CharConverter(arg).visit(arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
start = s;
|
||||
|
||||
// Format argument.
|
||||
AF(writer_, spec).visit(arg);
|
||||
}
|
||||
write(writer_, start, s);
|
||||
}
|
||||
|
||||
inline void printf(Writer &w, CStringRef format, ArgList args) {
|
||||
PrintfFormatter<char>(args, w).format(format);
|
||||
}
|
||||
FMT_VARIADIC(void, printf, Writer &, CStringRef)
|
||||
|
||||
inline void printf(WWriter &w, WCStringRef format, ArgList args) {
|
||||
PrintfFormatter<wchar_t>(args, w).format(format);
|
||||
}
|
||||
FMT_VARIADIC(void, printf, WWriter &, WCStringRef)
|
||||
|
||||
/**
|
||||
\rst
|
||||
Formats arguments and returns the result as a string.
|
||||
|
||||
**Example**::
|
||||
|
||||
std::string message = fmt::sprintf("The answer is %d", 42);
|
||||
\endrst
|
||||
*/
|
||||
inline std::string sprintf(CStringRef format, ArgList args) {
|
||||
MemoryWriter w;
|
||||
printf(w, format, args);
|
||||
return w.str();
|
||||
}
|
||||
FMT_VARIADIC(std::string, sprintf, CStringRef)
|
||||
|
||||
inline std::wstring sprintf(WCStringRef format, ArgList args) {
|
||||
WMemoryWriter w;
|
||||
printf(w, format, args);
|
||||
return w.str();
|
||||
}
|
||||
FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the file *f*.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::fprintf(stderr, "Don't %s!", "panic");
|
||||
\endrst
|
||||
*/
|
||||
FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);
|
||||
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to ``stdout``.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
||||
\endrst
|
||||
*/
|
||||
inline int printf(CStringRef format, ArgList args) {
|
||||
return fprintf(stdout, format, args);
|
||||
}
|
||||
FMT_VARIADIC(int, printf, CStringRef)
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the stream *os*.
|
||||
|
||||
**Example**::
|
||||
|
||||
fprintf(cerr, "Don't %s!", "panic");
|
||||
\endrst
|
||||
*/
|
||||
inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) {
|
||||
MemoryWriter w;
|
||||
printf(w, format_str, args);
|
||||
internal::write(os, w);
|
||||
return static_cast<int>(w.size());
|
||||
}
|
||||
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
|
||||
} // namespace fmt
|
||||
|
||||
#ifdef FMT_HEADER_ONLY
|
||||
# include "printf.cc"
|
||||
#endif
|
||||
|
||||
#endif // FMT_PRINTF_H_
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
Formatting library for C++ - string utilities
|
||||
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
#ifndef FMT_STRING_H_
|
||||
#define FMT_STRING_H_
|
||||
|
||||
#include "format.h"
|
||||
|
||||
namespace fmt {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// A buffer that stores data in ``std::basic_string``.
|
||||
template <typename Char, typename Allocator = std::allocator<Char> >
|
||||
class StringBuffer : public Buffer<Char> {
|
||||
public:
|
||||
typedef std::basic_string<Char, std::char_traits<Char>, Allocator> StringType;
|
||||
|
||||
private:
|
||||
StringType data_;
|
||||
|
||||
protected:
|
||||
virtual void grow(std::size_t size) FMT_OVERRIDE {
|
||||
data_.resize(size);
|
||||
this->ptr_ = &data_[0];
|
||||
this->capacity_ = size;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit StringBuffer(const Allocator &allocator = Allocator())
|
||||
: data_(allocator) {}
|
||||
|
||||
// Moves the data to ``str`` clearing the buffer.
|
||||
void move_to(StringType &str) {
|
||||
data_.resize(this->size_);
|
||||
str.swap(data_);
|
||||
this->capacity_ = this->size_ = 0;
|
||||
this->ptr_ = FMT_NULL;
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
\rst
|
||||
This class template provides operations for formatting and writing data
|
||||
into a character stream. The output is stored in a ``std::basic_string``
|
||||
that grows dynamically.
|
||||
|
||||
You can use one of the following typedefs for common character types
|
||||
and the standard allocator:
|
||||
|
||||
+---------------+----------------------------+
|
||||
| Type | Definition |
|
||||
+===============+============================+
|
||||
| StringWriter | BasicStringWriter<char> |
|
||||
+---------------+----------------------------+
|
||||
| WStringWriter | BasicStringWriter<wchar_t> |
|
||||
+---------------+----------------------------+
|
||||
|
||||
**Example**::
|
||||
|
||||
StringWriter out;
|
||||
out << "The answer is " << 42 << "\n";
|
||||
|
||||
This will write the following output to the ``out`` object:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
The answer is 42
|
||||
|
||||
The output can be moved to a ``std::basic_string`` with ``out.move_to()``.
|
||||
\endrst
|
||||
*/
|
||||
template <typename Char, typename Allocator = std::allocator<Char> >
|
||||
class BasicStringWriter : public BasicWriter<Char> {
|
||||
private:
|
||||
internal::StringBuffer<Char, Allocator> buffer_;
|
||||
|
||||
public:
|
||||
/**
|
||||
\rst
|
||||
Constructs a :class:`fmt::BasicStringWriter` object.
|
||||
\endrst
|
||||
*/
|
||||
explicit BasicStringWriter(const Allocator &allocator = Allocator())
|
||||
: BasicWriter<Char>(buffer_), buffer_(allocator) {}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Moves the buffer content to *str* clearing the buffer.
|
||||
\endrst
|
||||
*/
|
||||
void move_to(std::basic_string<Char, std::char_traits<Char>, Allocator> &str) {
|
||||
buffer_.move_to(str);
|
||||
}
|
||||
};
|
||||
|
||||
typedef BasicStringWriter<char> StringWriter;
|
||||
typedef BasicStringWriter<wchar_t> WStringWriter;
|
||||
|
||||
/**
|
||||
\rst
|
||||
Converts *value* to ``std::string`` using the default format for type *T*.
|
||||
|
||||
**Example**::
|
||||
|
||||
#include "fmt/string.h"
|
||||
|
||||
std::string answer = fmt::to_string(42);
|
||||
\endrst
|
||||
*/
|
||||
template <typename T>
|
||||
std::string to_string(const T &value) {
|
||||
fmt::MemoryWriter w;
|
||||
w << value;
|
||||
return w.str();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FMT_STRING_H_
|
||||
+102
-23
@@ -4,37 +4,25 @@
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
#ifndef FMT_TIME_H_
|
||||
#define FMT_TIME_H_
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "format.h"
|
||||
#include <ctime>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4702) // unreachable code
|
||||
# pragma warning(disable: 4996) // "deprecated" functions
|
||||
#endif
|
||||
|
||||
namespace fmt {
|
||||
template <typename ArgFormatter>
|
||||
void format(BasicFormatter<char, ArgFormatter> &f,
|
||||
const char *&format_str, const std::tm &tm) {
|
||||
void format_arg(BasicFormatter<char, ArgFormatter> &f,
|
||||
const char *&format_str, const std::tm &tm) {
|
||||
if (*format_str == ':')
|
||||
++format_str;
|
||||
const char *end = format_str;
|
||||
@@ -54,11 +42,102 @@ void format(BasicFormatter<char, ArgFormatter> &f,
|
||||
buffer.resize(start + count);
|
||||
break;
|
||||
}
|
||||
if (size >= format.size() * 256) {
|
||||
// If the buffer is 256 times larger than the format string, assume
|
||||
// that `strftime` gives an empty result. There doesn't seem to be a
|
||||
// better way to distinguish the two cases:
|
||||
// https://github.com/fmtlib/fmt/issues/367
|
||||
break;
|
||||
}
|
||||
const std::size_t MIN_GROWTH = 10;
|
||||
buffer.reserve(buffer.capacity() + size > MIN_GROWTH ? size : MIN_GROWTH);
|
||||
buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
|
||||
}
|
||||
format_str = end + 1;
|
||||
}
|
||||
|
||||
namespace internal{
|
||||
inline Null<> localtime_r(...) { return Null<>(); }
|
||||
inline Null<> localtime_s(...) { return Null<>(); }
|
||||
inline Null<> gmtime_r(...) { return Null<>(); }
|
||||
inline Null<> gmtime_s(...) { return Null<>(); }
|
||||
}
|
||||
|
||||
// Thread-safe replacement for std::localtime
|
||||
inline std::tm localtime(std::time_t time) {
|
||||
struct LocalTime {
|
||||
std::time_t time_;
|
||||
std::tm tm_;
|
||||
|
||||
LocalTime(std::time_t t): time_(t) {}
|
||||
|
||||
bool run() {
|
||||
using namespace fmt::internal;
|
||||
return handle(localtime_r(&time_, &tm_));
|
||||
}
|
||||
|
||||
bool handle(std::tm *tm) { return tm != FMT_NULL; }
|
||||
|
||||
bool handle(internal::Null<>) {
|
||||
using namespace fmt::internal;
|
||||
return fallback(localtime_s(&tm_, &time_));
|
||||
}
|
||||
|
||||
bool fallback(int res) { return res == 0; }
|
||||
|
||||
bool fallback(internal::Null<>) {
|
||||
using namespace fmt::internal;
|
||||
std::tm *tm = std::localtime(&time_);
|
||||
if (tm) tm_ = *tm;
|
||||
return tm != FMT_NULL;
|
||||
}
|
||||
};
|
||||
LocalTime lt(time);
|
||||
if (lt.run())
|
||||
return lt.tm_;
|
||||
// Too big time values may be unsupported.
|
||||
FMT_THROW(fmt::FormatError("time_t value out of range"));
|
||||
return std::tm();
|
||||
}
|
||||
|
||||
// Thread-safe replacement for std::gmtime
|
||||
inline std::tm gmtime(std::time_t time) {
|
||||
struct GMTime {
|
||||
std::time_t time_;
|
||||
std::tm tm_;
|
||||
|
||||
GMTime(std::time_t t): time_(t) {}
|
||||
|
||||
bool run() {
|
||||
using namespace fmt::internal;
|
||||
return handle(gmtime_r(&time_, &tm_));
|
||||
}
|
||||
|
||||
bool handle(std::tm *tm) { return tm != FMT_NULL; }
|
||||
|
||||
bool handle(internal::Null<>) {
|
||||
using namespace fmt::internal;
|
||||
return fallback(gmtime_s(&tm_, &time_));
|
||||
}
|
||||
|
||||
bool fallback(int res) { return res == 0; }
|
||||
|
||||
bool fallback(internal::Null<>) {
|
||||
std::tm *tm = std::gmtime(&time_);
|
||||
if (tm != FMT_NULL) tm_ = *tm;
|
||||
return tm != FMT_NULL;
|
||||
}
|
||||
};
|
||||
GMTime gt(time);
|
||||
if (gt.run())
|
||||
return gt.tm_;
|
||||
// Too big time values may be unsupported.
|
||||
FMT_THROW(fmt::FormatError("time_t value out of range"));
|
||||
return std::tm();
|
||||
}
|
||||
} //namespace fmt
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // FMT_TIME_H_
|
||||
|
||||
@@ -10,22 +10,23 @@ platform = os.environ.get('PLATFORM')
|
||||
path = os.environ['PATH']
|
||||
cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config]
|
||||
if build == 'mingw':
|
||||
cmake_command.append('-GMinGW Makefiles')
|
||||
build_command = ['mingw32-make', '-j4']
|
||||
test_command = ['mingw32-make', 'test']
|
||||
# Remove the path to Git bin directory from $PATH because it breaks MinGW config.
|
||||
path = path.replace(r'C:\Program Files (x86)\Git\bin', '')
|
||||
os.environ['PATH'] = r'C:\MinGW\bin;' + path
|
||||
cmake_command.append('-GMinGW Makefiles')
|
||||
build_command = ['mingw32-make', '-j4']
|
||||
test_command = ['mingw32-make', 'test']
|
||||
# Remove the path to Git bin directory from $PATH because it breaks
|
||||
# MinGW config.
|
||||
path = path.replace(r'C:\Program Files (x86)\Git\bin', '')
|
||||
os.environ['PATH'] = r'C:\MinGW\bin;' + path
|
||||
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 = ['cmake', '--build', '.', '--config', config, '--', '/m:4']
|
||||
test_command = ['ctest', '-C', config]
|
||||
# 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 = ['cmake', '--build', '.', '--config', config, '--', '/m:4']
|
||||
test_command = ['ctest', '-C', config]
|
||||
|
||||
check_call(cmake_command)
|
||||
check_call(build_command)
|
||||
|
||||
@@ -20,3 +20,7 @@ build_script:
|
||||
on_failure:
|
||||
- appveyor PushArtifact Testing/Temporary/LastTest.log
|
||||
- appveyor AddTest test
|
||||
|
||||
# Uncomment this to debug AppVeyor failures.
|
||||
#on_finish:
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
|
||||
@@ -20,7 +20,14 @@ if (FMT_USE_CPP11)
|
||||
check_cxx_source_compiles("
|
||||
#include <unistd.h>
|
||||
int main() {}" FMT_CPP11_UNISTD_H)
|
||||
if (FMT_CPP11_CMATH AND FMT_CPP11_UNISTD_H)
|
||||
# Check if snprintf works with -std=c++11. It may not in MinGW.
|
||||
check_cxx_source_compiles("
|
||||
#include <stdio.h>
|
||||
int main() {
|
||||
char buffer[10];
|
||||
snprintf(buffer, 10, \"foo\");
|
||||
}" FMT_CPP11_SNPRINTF)
|
||||
if (FMT_CPP11_CMATH AND FMT_CPP11_UNISTD_H AND FMT_CPP11_SNPRINTF)
|
||||
set(CPP11_FLAG -std=c++11)
|
||||
else ()
|
||||
check_cxx_compiler_flag(-std=gnu++11 HAVE_STD_GNUPP11_FLAG)
|
||||
@@ -37,6 +44,11 @@ if (FMT_USE_CPP11)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (CMAKE_CXX_STANDARD)
|
||||
# Don't use -std compiler flag if CMAKE_CXX_STANDARD is specified.
|
||||
set(CPP11_FLAG )
|
||||
endif ()
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS ${CPP11_FLAG})
|
||||
|
||||
# Check if variadic templates are working and not affected by GCC bug 39653:
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""Manage site and releases.
|
||||
|
||||
Usage:
|
||||
manage.py release [<branch>]
|
||||
manage.py site
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import datetime, docopt, fileinput, json, os
|
||||
import re, requests, shutil, sys, tempfile
|
||||
from contextlib import contextmanager
|
||||
from distutils.version import LooseVersion
|
||||
from subprocess import check_call
|
||||
|
||||
|
||||
class Git:
|
||||
def __init__(self, dir):
|
||||
self.dir = dir
|
||||
|
||||
def call(self, method, args, **kwargs):
|
||||
return check_call(['git', method] + list(args), **kwargs)
|
||||
|
||||
def add(self, *args):
|
||||
return self.call('add', args, cwd=self.dir)
|
||||
|
||||
def checkout(self, *args):
|
||||
return self.call('checkout', args, cwd=self.dir)
|
||||
|
||||
def clean(self, *args):
|
||||
return self.call('clean', args, cwd=self.dir)
|
||||
|
||||
def clone(self, *args):
|
||||
return self.call('clone', list(args) + [self.dir])
|
||||
|
||||
def commit(self, *args):
|
||||
return self.call('commit', args, cwd=self.dir)
|
||||
|
||||
def pull(self, *args):
|
||||
return self.call('pull', args, cwd=self.dir)
|
||||
|
||||
def push(self, *args):
|
||||
return self.call('push', args, cwd=self.dir)
|
||||
|
||||
def reset(self, *args):
|
||||
return self.call('reset', args, cwd=self.dir)
|
||||
|
||||
def update(self, *args):
|
||||
clone = not os.path.exists(self.dir)
|
||||
if clone:
|
||||
self.clone(*args)
|
||||
return clone
|
||||
|
||||
|
||||
def clean_checkout(repo, branch):
|
||||
repo.clean('-f', '-d')
|
||||
repo.reset('--hard')
|
||||
repo.checkout(branch)
|
||||
|
||||
|
||||
class Runner:
|
||||
def __init__(self, cwd):
|
||||
self.cwd = cwd
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
kwargs['cwd'] = kwargs.get('cwd', self.cwd)
|
||||
check_call(args, **kwargs)
|
||||
|
||||
|
||||
def create_build_env():
|
||||
"""Create a build environment."""
|
||||
class Env:
|
||||
pass
|
||||
env = Env()
|
||||
|
||||
# Import the documentation build module.
|
||||
env.fmt_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, os.path.join(env.fmt_dir, 'doc'))
|
||||
import build
|
||||
|
||||
env.build_dir = 'build'
|
||||
|
||||
# Virtualenv and repos are cached to speed up builds.
|
||||
build.create_build_env(os.path.join(env.build_dir, 'virtualenv'))
|
||||
|
||||
env.fmt_repo = Git(os.path.join(env.build_dir, 'fmt'))
|
||||
return env
|
||||
|
||||
|
||||
@contextmanager
|
||||
def rewrite(filename):
|
||||
class Buffer:
|
||||
pass
|
||||
buffer = Buffer()
|
||||
if not os.path.exists(filename):
|
||||
buffer.data = ''
|
||||
yield buffer
|
||||
return
|
||||
with open(filename) as f:
|
||||
buffer.data = f.read()
|
||||
yield buffer
|
||||
with open(filename, 'w') as f:
|
||||
f.write(buffer.data)
|
||||
|
||||
|
||||
fmt_repo_url = 'git@github.com:fmtlib/fmt'
|
||||
|
||||
|
||||
def update_site(env):
|
||||
env.fmt_repo.update(fmt_repo_url)
|
||||
|
||||
doc_repo = Git(os.path.join(env.build_dir, 'fmtlib.github.io'))
|
||||
doc_repo.update('git@github.com:fmtlib/fmtlib.github.io')
|
||||
|
||||
for version in ['1.0.0', '1.1.0', '2.0.0', '3.0.0']:
|
||||
clean_checkout(env.fmt_repo, version)
|
||||
target_doc_dir = os.path.join(env.fmt_repo.dir, 'doc')
|
||||
# Remove the old theme.
|
||||
for entry in os.listdir(target_doc_dir):
|
||||
path = os.path.join(target_doc_dir, entry)
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
# Copy the new theme.
|
||||
for entry in ['_static', '_templates', 'basic-bootstrap', 'bootstrap',
|
||||
'conf.py', 'fmt.less']:
|
||||
src = os.path.join(env.fmt_dir, 'doc', entry)
|
||||
dst = os.path.join(target_doc_dir, entry)
|
||||
copy = shutil.copytree if os.path.isdir(src) else shutil.copyfile
|
||||
copy(src, dst)
|
||||
# Rename index to contents.
|
||||
contents = os.path.join(target_doc_dir, 'contents.rst')
|
||||
if not os.path.exists(contents):
|
||||
os.rename(os.path.join(target_doc_dir, 'index.rst'), contents)
|
||||
# Fix issues in reference.rst/api.rst.
|
||||
for filename in ['reference.rst', 'api.rst']:
|
||||
pattern = re.compile('doxygenfunction.. (bin|oct|hexu|hex)$', re.M)
|
||||
with rewrite(os.path.join(target_doc_dir, filename)) as b:
|
||||
b.data = b.data.replace('std::ostream &', 'std::ostream&')
|
||||
b.data = re.sub(pattern, r'doxygenfunction:: \1(int)', b.data)
|
||||
b.data = b.data.replace('std::FILE*', 'std::FILE *')
|
||||
b.data = b.data.replace('unsigned int', 'unsigned')
|
||||
# Fix a broken link in index.rst.
|
||||
index = os.path.join(target_doc_dir, 'index.rst')
|
||||
with rewrite(index) as b:
|
||||
b.data = b.data.replace(
|
||||
'doc/latest/index.html#format-string-syntax', 'syntax.html')
|
||||
# Build the docs.
|
||||
html_dir = os.path.join(env.build_dir, 'html')
|
||||
if os.path.exists(html_dir):
|
||||
shutil.rmtree(html_dir)
|
||||
include_dir = env.fmt_repo.dir
|
||||
if LooseVersion(version) >= LooseVersion('3.0.0'):
|
||||
include_dir = os.path.join(include_dir, 'fmt')
|
||||
import build
|
||||
build.build_docs(version, doc_dir=target_doc_dir,
|
||||
include_dir=include_dir, work_dir=env.build_dir)
|
||||
shutil.rmtree(os.path.join(html_dir, '.doctrees'))
|
||||
# Create symlinks for older versions.
|
||||
for link, target in {'index': 'contents', 'api': 'reference'}.items():
|
||||
link = os.path.join(html_dir, link) + '.html'
|
||||
target += '.html'
|
||||
if os.path.exists(os.path.join(html_dir, target)) and \
|
||||
not os.path.exists(link):
|
||||
os.symlink(target, link)
|
||||
# Copy docs to the website.
|
||||
version_doc_dir = os.path.join(doc_repo.dir, version)
|
||||
shutil.rmtree(version_doc_dir)
|
||||
shutil.move(html_dir, version_doc_dir)
|
||||
|
||||
|
||||
def release(args):
|
||||
env = create_build_env()
|
||||
fmt_repo = env.fmt_repo
|
||||
|
||||
branch = args.get('<branch>')
|
||||
if branch is None:
|
||||
branch = 'master'
|
||||
if not fmt_repo.update('-b', branch, fmt_repo_url):
|
||||
clean_checkout(fmt_repo, branch)
|
||||
|
||||
# Convert changelog from RST to GitHub-flavored Markdown and get the
|
||||
# version.
|
||||
changelog = 'ChangeLog.rst'
|
||||
changelog_path = os.path.join(fmt_repo.dir, changelog)
|
||||
import rst2md
|
||||
changes, version = rst2md.convert(changelog_path)
|
||||
cmakelists = 'CMakeLists.txt'
|
||||
for line in fileinput.input(os.path.join(fmt_repo.dir, cmakelists),
|
||||
inplace=True):
|
||||
prefix = 'set(FMT_VERSION '
|
||||
if line.startswith(prefix):
|
||||
line = prefix + version + ')\n'
|
||||
sys.stdout.write(line)
|
||||
|
||||
# Update the version in the changelog.
|
||||
title_len = 0
|
||||
for line in fileinput.input(changelog_path, inplace=True):
|
||||
if line.decode('utf-8').startswith(version + ' - TBD'):
|
||||
line = version + ' - ' + datetime.date.today().isoformat()
|
||||
title_len = len(line)
|
||||
line += '\n'
|
||||
elif title_len:
|
||||
line = '-' * title_len + '\n'
|
||||
title_len = 0
|
||||
sys.stdout.write(line)
|
||||
# TODO: add new version to manage.py
|
||||
fmt_repo.checkout('-B', 'release')
|
||||
fmt_repo.add(changelog, cmakelists)
|
||||
fmt_repo.commit('-m', 'Update version')
|
||||
|
||||
# Build the docs and package.
|
||||
run = Runner(fmt_repo.dir)
|
||||
run('cmake', '.')
|
||||
run('make', 'doc', 'package_source')
|
||||
|
||||
update_site(env)
|
||||
|
||||
# Create a release on GitHub.
|
||||
fmt_repo.push('origin', 'release')
|
||||
r = requests.post('https://api.github.com/repos/fmtlib/fmt/releases',
|
||||
params={'access_token': os.getenv('FMT_TOKEN')},
|
||||
data=json.dumps({'tag_name': version,
|
||||
'target_commitish': 'release',
|
||||
'body': changes, 'draft': True}))
|
||||
if r.status_code != 201:
|
||||
raise Exception('Failed to create a release ' + str(r))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = docopt.docopt(__doc__)
|
||||
if args.get('release'):
|
||||
release(args)
|
||||
elif args.get('site'):
|
||||
update_site(create_build_env())
|
||||
@@ -0,0 +1,127 @@
|
||||
# reStructuredText (RST) to GitHub-flavored Markdown converter
|
||||
|
||||
import re
|
||||
from docutils import core, nodes, writers
|
||||
|
||||
|
||||
def is_github_ref(node):
|
||||
return re.match('https://github.com/.*/(issues|pull)/.*', node['refuri'])
|
||||
|
||||
|
||||
class Translator(nodes.NodeVisitor):
|
||||
def __init__(self, document):
|
||||
nodes.NodeVisitor.__init__(self, document)
|
||||
self.output = ''
|
||||
self.indent = 0
|
||||
self.preserve_newlines = False
|
||||
|
||||
def write(self, text):
|
||||
self.output += text.replace('\n', '\n' + ' ' * self.indent)
|
||||
|
||||
def visit_document(self, node):
|
||||
pass
|
||||
|
||||
def depart_document(self, node):
|
||||
pass
|
||||
|
||||
def visit_section(self, node):
|
||||
pass
|
||||
|
||||
def depart_section(self, node):
|
||||
# Skip all sections except the first one.
|
||||
raise nodes.StopTraversal
|
||||
|
||||
def visit_title(self, node):
|
||||
self.version = re.match(r'(\d+\.\d+\.\d+).*', node.children[0]).group(1)
|
||||
raise nodes.SkipChildren
|
||||
|
||||
def depart_title(self, node):
|
||||
pass
|
||||
|
||||
def visit_Text(self, node):
|
||||
if not self.preserve_newlines:
|
||||
node = node.replace('\n', ' ')
|
||||
self.write(node)
|
||||
|
||||
def depart_Text(self, node):
|
||||
pass
|
||||
|
||||
def visit_bullet_list(self, node):
|
||||
pass
|
||||
|
||||
def depart_bullet_list(self, node):
|
||||
pass
|
||||
|
||||
def visit_list_item(self, node):
|
||||
self.write('* ')
|
||||
self.indent += 2
|
||||
|
||||
def depart_list_item(self, node):
|
||||
self.indent -= 2
|
||||
self.write('\n\n')
|
||||
|
||||
def visit_paragraph(self, node):
|
||||
pass
|
||||
|
||||
def depart_paragraph(self, node):
|
||||
pass
|
||||
|
||||
def visit_reference(self, node):
|
||||
if not is_github_ref(node):
|
||||
self.write('[')
|
||||
|
||||
def depart_reference(self, node):
|
||||
if not is_github_ref(node):
|
||||
self.write('](' + node['refuri'] + ')')
|
||||
|
||||
def visit_target(self, node):
|
||||
pass
|
||||
|
||||
def depart_target(self, node):
|
||||
pass
|
||||
|
||||
def visit_literal(self, node):
|
||||
self.write('`')
|
||||
|
||||
def depart_literal(self, node):
|
||||
self.write('`')
|
||||
|
||||
def visit_literal_block(self, node):
|
||||
self.write('\n\n```')
|
||||
if 'c++' in node['classes']:
|
||||
self.write('c++')
|
||||
self.write('\n')
|
||||
self.preserve_newlines = True
|
||||
|
||||
def depart_literal_block(self, node):
|
||||
self.write('\n```\n')
|
||||
self.preserve_newlines = False
|
||||
|
||||
def visit_inline(self, node):
|
||||
pass
|
||||
|
||||
def depart_inline(self, node):
|
||||
pass
|
||||
|
||||
def visit_image(self, node):
|
||||
self.write('')
|
||||
|
||||
def depart_image(self, node):
|
||||
pass
|
||||
|
||||
|
||||
class MDWriter(writers.Writer):
|
||||
"""GitHub-flavored markdown writer"""
|
||||
|
||||
supported = ('md',)
|
||||
"""Formats this writer supports."""
|
||||
|
||||
def translate(self):
|
||||
translator = Translator(self.document)
|
||||
self.document.walkabout(translator)
|
||||
self.output = (translator.output, translator.version)
|
||||
|
||||
|
||||
def convert(rst_path):
|
||||
"""Converts RST file to Markdown."""
|
||||
return core.publish_file(source_path=rst_path, writer=MDWriter())
|
||||
@@ -6,34 +6,28 @@ import errno, os, re, shutil, sys, tempfile, urllib
|
||||
from subprocess import call, check_call, check_output, Popen, PIPE, STDOUT
|
||||
|
||||
def rmtree_if_exists(dir):
|
||||
try:
|
||||
shutil.rmtree(dir)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
pass
|
||||
try:
|
||||
shutil.rmtree(dir)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
pass
|
||||
|
||||
def makedirs_if_not_exist(dir):
|
||||
try:
|
||||
os.makedirs(dir)
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
try:
|
||||
os.makedirs(dir)
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
fmt_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
build = os.environ['BUILD']
|
||||
if build == 'Doc':
|
||||
travis = 'TRAVIS' in os.environ
|
||||
# Install dependencies.
|
||||
if travis:
|
||||
def install_dependencies():
|
||||
branch = os.environ['TRAVIS_BRANCH']
|
||||
if branch != 'master':
|
||||
print('Branch: ' + branch)
|
||||
exit(0) # Ignore non-master branches
|
||||
check_call('curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | ' +
|
||||
'sudo apt-key add -', shell=True)
|
||||
check_call('echo "deb https://deb.nodesource.com/node_0.10 precise main" | ' +
|
||||
'sudo tee /etc/apt/sources.list.d/nodesource.list', shell=True)
|
||||
print('Branch: ' + branch)
|
||||
exit(0) # Ignore non-master branches
|
||||
check_call('curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key ' +
|
||||
'| sudo apt-key add -', shell=True)
|
||||
check_call('echo "deb https://deb.nodesource.com/node_0.10 precise main" ' +
|
||||
'| sudo tee /etc/apt/sources.list.d/nodesource.list', shell=True)
|
||||
check_call(['sudo', 'apt-get', 'update'])
|
||||
check_call(['sudo', 'apt-get', 'install', 'python-virtualenv', 'nodejs'])
|
||||
check_call(['npm', 'install', '-g', 'less', 'less-plugin-clean-css'])
|
||||
@@ -41,39 +35,48 @@ if build == 'Doc':
|
||||
urllib.urlretrieve('http://mirrors.kernel.org/ubuntu/pool/main/d/doxygen/' +
|
||||
deb_file, deb_file)
|
||||
check_call(['sudo', 'dpkg', '-i', deb_file])
|
||||
sys.path.insert(0, os.path.join(fmt_dir, 'doc'))
|
||||
import build
|
||||
html_dir = build.build_docs()
|
||||
repo = 'fmtlib.github.io'
|
||||
if travis and 'KEY' not in os.environ:
|
||||
# Don't update the repo if building on Travis from an account that doesn't
|
||||
# have push access.
|
||||
print('Skipping update of ' + repo)
|
||||
exit(0)
|
||||
# Clone the fmtlib.github.io repo.
|
||||
rmtree_if_exists(repo)
|
||||
git_url = 'https://github.com/' if travis else 'git@github.com:'
|
||||
check_call(['git', 'clone', git_url + 'fmtlib/{}.git'.format(repo)])
|
||||
# Copy docs to the repo.
|
||||
target_dir = os.path.join(repo, 'dev')
|
||||
rmtree_if_exists(target_dir)
|
||||
shutil.copytree(html_dir, target_dir, ignore=shutil.ignore_patterns('.*'))
|
||||
if travis:
|
||||
check_call(['git', 'config', '--global', 'user.name', 'amplbot'])
|
||||
check_call(['git', 'config', '--global', 'user.email', 'viz@ampl.com'])
|
||||
# Push docs to GitHub pages.
|
||||
check_call(['git', 'add', '--all'], cwd=repo)
|
||||
if call(['git', 'diff-index', '--quiet', 'HEAD'], cwd=repo):
|
||||
check_call(['git', 'commit', '-m', 'Update documentation'], cwd=repo)
|
||||
cmd = 'git push'
|
||||
|
||||
fmt_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
build = os.environ['BUILD']
|
||||
if build == 'Doc':
|
||||
travis = 'TRAVIS' in os.environ
|
||||
if travis:
|
||||
cmd += ' https://$KEY@github.com/fmtlib/fmtlib.github.io.git master'
|
||||
p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=repo)
|
||||
# Print the output without the key.
|
||||
print(p.communicate()[0].replace(os.environ['KEY'], '$KEY'))
|
||||
if p.returncode != 0:
|
||||
raise CalledProcessError(p.returncode, cmd)
|
||||
exit(0)
|
||||
install_dependencies()
|
||||
sys.path.insert(0, os.path.join(fmt_dir, 'doc'))
|
||||
import build
|
||||
build.create_build_env()
|
||||
html_dir = build.build_docs()
|
||||
repo = 'fmtlib.github.io'
|
||||
if travis and 'KEY' not in os.environ:
|
||||
# Don't update the repo if building on Travis from an account that
|
||||
# doesn't have push access.
|
||||
print('Skipping update of ' + repo)
|
||||
exit(0)
|
||||
# Clone the fmtlib.github.io repo.
|
||||
rmtree_if_exists(repo)
|
||||
git_url = 'https://github.com/' if travis else 'git@github.com:'
|
||||
check_call(['git', 'clone', git_url + 'fmtlib/{}.git'.format(repo)])
|
||||
# Copy docs to the repo.
|
||||
target_dir = os.path.join(repo, 'dev')
|
||||
rmtree_if_exists(target_dir)
|
||||
shutil.copytree(html_dir, target_dir, ignore=shutil.ignore_patterns('.*'))
|
||||
if travis:
|
||||
check_call(['git', 'config', '--global', 'user.name', 'amplbot'])
|
||||
check_call(['git', 'config', '--global', 'user.email', 'viz@ampl.com'])
|
||||
# Push docs to GitHub pages.
|
||||
check_call(['git', 'add', '--all'], cwd=repo)
|
||||
if call(['git', 'diff-index', '--quiet', 'HEAD'], cwd=repo):
|
||||
check_call(['git', 'commit', '-m', 'Update documentation'], cwd=repo)
|
||||
cmd = 'git push'
|
||||
if travis:
|
||||
cmd += ' https://$KEY@github.com/fmtlib/fmtlib.github.io.git master'
|
||||
p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=repo)
|
||||
# Print the output without the key.
|
||||
print(p.communicate()[0].replace(os.environ['KEY'], '$KEY'))
|
||||
if p.returncode != 0:
|
||||
raise CalledProcessError(p.returncode, cmd)
|
||||
exit(0)
|
||||
|
||||
standard = os.environ['STANDARD']
|
||||
install_dir = os.path.join(fmt_dir, "_install")
|
||||
@@ -83,11 +86,13 @@ test_build_dir = os.path.join(fmt_dir, "_build_test")
|
||||
# Configure library.
|
||||
makedirs_if_not_exist(build_dir)
|
||||
common_cmake_flags = [
|
||||
'-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build
|
||||
'-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build
|
||||
]
|
||||
extra_cmake_flags = []
|
||||
if standard != '0x':
|
||||
extra_cmake_flags = ['-DCMAKE_CXX_FLAGS=-std=c++' + standard, '-DFMT_USE_CPP11=OFF']
|
||||
extra_cmake_flags = [
|
||||
'-DCMAKE_CXX_FLAGS=-std=c++' + standard, '-DFMT_USE_CPP11=OFF'
|
||||
]
|
||||
check_call(['cmake', '-DFMT_DOC=OFF', '-DFMT_PEDANTIC=ON', fmt_dir] +
|
||||
common_cmake_flags + extra_cmake_flags, cwd=build_dir)
|
||||
|
||||
@@ -98,9 +103,9 @@ check_call(['make', '-j4'], cwd=build_dir)
|
||||
env = os.environ.copy()
|
||||
env['CTEST_OUTPUT_ON_FAILURE'] = '1'
|
||||
if call(['make', 'test'], env=env, cwd=build_dir):
|
||||
with open('Testing/Temporary/LastTest.log', 'r') as f:
|
||||
print(f.read())
|
||||
sys.exit(-1)
|
||||
with open('Testing/Temporary/LastTest.log', 'r') as f:
|
||||
print(f.read())
|
||||
sys.exit(-1)
|
||||
|
||||
# Install library.
|
||||
check_call(['make', 'install'], cwd=build_dir)
|
||||
|
||||
@@ -8,23 +8,23 @@ import shutil, tempfile
|
||||
from subprocess import check_output, STDOUT
|
||||
|
||||
class Git:
|
||||
def __init__(self, dir):
|
||||
self.dir = dir
|
||||
def __init__(self, dir):
|
||||
self.dir = dir
|
||||
|
||||
def __call__(self, *args):
|
||||
output = check_output(['git'] + list(args), cwd=self.dir, stderr=STDOUT)
|
||||
print(output)
|
||||
return output
|
||||
def __call__(self, *args):
|
||||
output = check_output(['git'] + list(args), cwd=self.dir, stderr=STDOUT)
|
||||
print(output)
|
||||
return output
|
||||
|
||||
dir = tempfile.mkdtemp()
|
||||
try:
|
||||
git = Git(dir)
|
||||
git('clone', '-b', 'coverity', 'git@github.com:fmtlib/fmt.git', dir)
|
||||
output = git('merge', '-X', 'theirs', '--no-commit', 'origin/master')
|
||||
if 'Fast-forward' not in output:
|
||||
git('reset', 'HEAD', '.travis.yml')
|
||||
git('checkout', '--', '.travis.yml')
|
||||
git('commit', '-m', 'Update coverity branch')
|
||||
git('push')
|
||||
git = Git(dir)
|
||||
git('clone', '-b', 'coverity', 'git@github.com:fmtlib/fmt.git', dir)
|
||||
output = git('merge', '-X', 'theirs', '--no-commit', 'origin/master')
|
||||
if 'Fast-forward' not in output:
|
||||
git('reset', 'HEAD', '.travis.yml')
|
||||
git('checkout', '--', '.travis.yml')
|
||||
git('commit', '-m', 'Update coverity branch')
|
||||
git('push')
|
||||
finally:
|
||||
shutil.rmtree(dir)
|
||||
shutil.rmtree(dir)
|
||||
|
||||
@@ -56,11 +56,19 @@ if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
||||
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wno-long-long -Wno-variadic-macros)
|
||||
endif ()
|
||||
|
||||
function(add_fmt_executable name)
|
||||
add_executable(${name} ${ARGN})
|
||||
if (MINGW)
|
||||
target_link_libraries(${name} -static-libgcc -static-libstdc++)
|
||||
endif ()
|
||||
endfunction()
|
||||
|
||||
# Adds a test.
|
||||
# Usage: add_fmt_test(name srcs...)
|
||||
function(add_fmt_test name)
|
||||
add_executable(${name} ${name}.cc ${ARGN})
|
||||
add_fmt_executable(${name} ${name}.cc ${ARGN})
|
||||
target_link_libraries(${name} test-main)
|
||||
|
||||
# define if certain c++ features can be used
|
||||
target_compile_definitions(${name} PRIVATE
|
||||
FMT_USE_TYPE_TRAITS=$<BOOL:${SUPPORTS_TYPE_TRAITS}>
|
||||
@@ -72,13 +80,17 @@ function(add_fmt_test name)
|
||||
endfunction()
|
||||
|
||||
add_fmt_test(assert-test)
|
||||
add_fmt_test(container-test)
|
||||
add_fmt_test(gtest-extra-test)
|
||||
add_fmt_test(format-test)
|
||||
add_fmt_test(format-impl-test)
|
||||
add_fmt_test(ostream-test)
|
||||
add_fmt_test(printf-test)
|
||||
add_fmt_test(string-test)
|
||||
add_fmt_test(time-test)
|
||||
add_fmt_test(util-test mock-allocator.h)
|
||||
add_fmt_test(macro-test)
|
||||
add_fmt_test(custom-formatter-test)
|
||||
|
||||
# Enable stricter options for one test to make sure that the header is free of
|
||||
# warnings.
|
||||
@@ -87,7 +99,8 @@ if (FMT_PEDANTIC AND MSVC)
|
||||
endif ()
|
||||
|
||||
if (HAVE_OPEN)
|
||||
add_executable(posix-mock-test posix-mock-test.cc ../fmt/format.cc ${TEST_MAIN_SRC})
|
||||
add_fmt_executable(posix-mock-test
|
||||
posix-mock-test.cc ../fmt/format.cc ../fmt/printf.cc ${TEST_MAIN_SRC})
|
||||
target_include_directories(posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR})
|
||||
target_compile_definitions(posix-mock-test PRIVATE FMT_USE_FILE_DESCRIPTORS=1)
|
||||
target_link_libraries(posix-mock-test gmock)
|
||||
@@ -95,7 +108,7 @@ if (HAVE_OPEN)
|
||||
add_fmt_test(posix-test)
|
||||
endif ()
|
||||
|
||||
add_executable(header-only-test
|
||||
add_fmt_executable(header-only-test
|
||||
header-only-test.cc header-only-test2.cc test-main.cc)
|
||||
target_link_libraries(header-only-test gmock)
|
||||
if (TARGET fmt-header-only)
|
||||
@@ -109,6 +122,7 @@ endif ()
|
||||
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
|
||||
if (HAVE_FNO_EXCEPTIONS_FLAG)
|
||||
add_library(noexception-test ../fmt/format.cc)
|
||||
target_include_directories(noexception-test PRIVATE ${PROJECT_SOURCE_DIR})
|
||||
target_compile_options(noexception-test PRIVATE -fno-exceptions)
|
||||
endif ()
|
||||
|
||||
@@ -116,6 +130,7 @@ if (FMT_PEDANTIC)
|
||||
# Test that the library compiles without windows.h.
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
add_library(no-windows-h-test ../fmt/format.cc)
|
||||
target_include_directories(no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR})
|
||||
target_compile_definitions(no-windows-h-test PRIVATE FMT_USE_WINDOWS_H=0)
|
||||
endif ()
|
||||
|
||||
@@ -125,7 +140,7 @@ if (FMT_PEDANTIC)
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/compile-test"
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
||||
--build-options
|
||||
--build-options
|
||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||
"-DCPP11_FLAG=${CPP11_FLAG}"
|
||||
"-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}")
|
||||
|
||||
@@ -5,9 +5,9 @@ project(fmt-test)
|
||||
add_subdirectory(../.. fmt)
|
||||
|
||||
add_executable(library-test "main.cc")
|
||||
target_link_libraries(library-test fmt)
|
||||
target_link_libraries(library-test fmt::fmt)
|
||||
|
||||
if (TARGET fmt-header-only)
|
||||
if (TARGET fmt::fmt-header-only)
|
||||
add_executable(header-only-test "main.cc")
|
||||
target_link_libraries(header-only-test fmt-header-only)
|
||||
target_link_libraries(header-only-test fmt::fmt-header-only)
|
||||
endif ()
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Tests of container utilities
|
||||
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
#include "fmt/container.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using fmt::internal::ContainerBuffer;
|
||||
|
||||
TEST(ContainerBufferTest, Empty) {
|
||||
std::string data;
|
||||
ContainerBuffer<std::string> buffer(data);
|
||||
EXPECT_EQ(0u, buffer.size());
|
||||
EXPECT_EQ(0u, buffer.capacity());
|
||||
}
|
||||
|
||||
TEST(ContainerBufferTest, Reserve) {
|
||||
std::string data;
|
||||
ContainerBuffer<std::string> buffer(data);
|
||||
std::size_t capacity = std::string().capacity() + 10;
|
||||
buffer.reserve(capacity);
|
||||
EXPECT_EQ(0u, buffer.size());
|
||||
EXPECT_EQ(capacity, buffer.capacity());
|
||||
}
|
||||
|
||||
TEST(ContainerBufferTest, Resize) {
|
||||
std::string data;
|
||||
ContainerBuffer<std::string> buffer(data);
|
||||
std::size_t size = std::string().capacity() + 10;
|
||||
buffer.resize(size);
|
||||
EXPECT_EQ(size, buffer.size());
|
||||
EXPECT_EQ(size, buffer.capacity());
|
||||
}
|
||||
|
||||
TEST(ContainerBufferTest, Append) {
|
||||
std::string data("Why so");
|
||||
const std::string serious(" serious");
|
||||
ContainerBuffer<std::string> buffer(data);
|
||||
buffer.append(serious.c_str(), serious.c_str() + serious.length());
|
||||
EXPECT_EQ("Why so serious", data);
|
||||
EXPECT_EQ(data.length(), buffer.size());
|
||||
}
|
||||
|
||||
TEST(BasicContainerWriterTest, String) {
|
||||
std::string data;
|
||||
fmt::BasicContainerWriter<std::string> out(data);
|
||||
out << "The answer is " << 42 << "\n";
|
||||
EXPECT_EQ("The answer is 42\n", data);
|
||||
EXPECT_EQ(17u, out.size());
|
||||
}
|
||||
|
||||
TEST(BasicContainerWriterTest, WString) {
|
||||
std::wstring data;
|
||||
fmt::BasicContainerWriter<std::wstring> out(data);
|
||||
out << "The answer is " << 42 << "\n";
|
||||
EXPECT_EQ(L"The answer is 42\n", data);
|
||||
EXPECT_EQ(17u, out.size());
|
||||
}
|
||||
|
||||
TEST(BasicContainerWriterTest, Vector) {
|
||||
std::vector<char> data;
|
||||
fmt::BasicContainerWriter<std::vector<char> > out(data);
|
||||
out << "The answer is " << 42 << "\n";
|
||||
EXPECT_EQ(17u, data.size());
|
||||
EXPECT_EQ(out.size(), data.size());
|
||||
}
|
||||
|
||||
TEST(BasicContainerWriterTest, StringAppend) {
|
||||
std::string data("The");
|
||||
fmt::BasicContainerWriter<std::string> out(data);
|
||||
EXPECT_EQ(3u, data.size());
|
||||
EXPECT_EQ(3u, out.size());
|
||||
out << " answer is " << 42 << "\n";
|
||||
EXPECT_EQ("The answer is 42\n", data);
|
||||
EXPECT_EQ(17u, out.size());
|
||||
}
|
||||
|
||||
TEST(BasicContainerWriterTest, VectorAppend) {
|
||||
std::vector<char> data;
|
||||
data.push_back('T');
|
||||
data.push_back('h');
|
||||
data.push_back('e');
|
||||
fmt::BasicContainerWriter<std::vector<char> > out(data);
|
||||
EXPECT_EQ(3u, data.size());
|
||||
EXPECT_EQ(3u, out.size());
|
||||
out << " answer is " << 42 << "\n";
|
||||
EXPECT_EQ(17u, data.size());
|
||||
EXPECT_EQ(17u, out.size());
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Custom argument formatter tests
|
||||
|
||||
Copyright (c) 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
#include "fmt/printf.h"
|
||||
#include "gtest-extra.h"
|
||||
|
||||
using fmt::BasicPrintfArgFormatter;
|
||||
|
||||
// A custom argument formatter that doesn't print `-` for floating-point values
|
||||
// rounded to 0.
|
||||
class CustomArgFormatter
|
||||
: public fmt::BasicArgFormatter<CustomArgFormatter, char> {
|
||||
public:
|
||||
CustomArgFormatter(fmt::BasicFormatter<char, CustomArgFormatter> &f,
|
||||
fmt::FormatSpec &s, const char *fmt)
|
||||
: fmt::BasicArgFormatter<CustomArgFormatter, char>(f, s, fmt) {}
|
||||
|
||||
void visit_double(double value) {
|
||||
if (round(value * pow(10, spec().precision())) == 0)
|
||||
value = 0;
|
||||
fmt::BasicArgFormatter<CustomArgFormatter, char>::visit_double(value);
|
||||
}
|
||||
};
|
||||
|
||||
// A custom argument formatter that doesn't print `-` for floating-point values
|
||||
// rounded to 0.
|
||||
class CustomPrintfArgFormatter :
|
||||
public BasicPrintfArgFormatter<CustomPrintfArgFormatter, char> {
|
||||
public:
|
||||
typedef BasicPrintfArgFormatter<CustomPrintfArgFormatter, char> Base;
|
||||
|
||||
CustomPrintfArgFormatter(fmt::BasicWriter<char> &w, fmt::FormatSpec &spec)
|
||||
: Base(w, spec) {}
|
||||
|
||||
void visit_double(double value) {
|
||||
if (round(value * pow(10, spec().precision())) == 0)
|
||||
value = 0;
|
||||
Base::visit_double(value);
|
||||
}
|
||||
};
|
||||
|
||||
std::string custom_format(const char *format_str, fmt::ArgList args) {
|
||||
fmt::MemoryWriter writer;
|
||||
// Pass custom argument formatter as a template arg to BasicFormatter.
|
||||
fmt::BasicFormatter<char, CustomArgFormatter> formatter(args, writer);
|
||||
formatter.format(format_str);
|
||||
return writer.str();
|
||||
}
|
||||
FMT_VARIADIC(std::string, custom_format, const char *)
|
||||
|
||||
std::string custom_sprintf(const char* format_str, fmt::ArgList args){
|
||||
fmt::MemoryWriter writer;
|
||||
fmt::PrintfFormatter<char, CustomPrintfArgFormatter> formatter(args, writer);
|
||||
formatter.format(format_str);
|
||||
return writer.str();
|
||||
}
|
||||
FMT_VARIADIC(std::string, custom_sprintf, const char*);
|
||||
|
||||
TEST(CustomFormatterTest, Format) {
|
||||
EXPECT_EQ("0.00", custom_format("{:.2f}", -.00001));
|
||||
EXPECT_EQ("0.00", custom_sprintf("%.2f", -.00001));
|
||||
}
|
||||
@@ -5,9 +5,9 @@ project(fmt-test)
|
||||
find_package(FMT REQUIRED)
|
||||
|
||||
add_executable(library-test main.cc)
|
||||
target_link_libraries(library-test fmt)
|
||||
target_link_libraries(library-test fmt::fmt)
|
||||
|
||||
if (TARGET fmt-header-only)
|
||||
if (TARGET fmt::fmt-header-only)
|
||||
add_executable(header-only-test main.cc)
|
||||
target_link_libraries(header-only-test fmt-header-only)
|
||||
target_link_libraries(header-only-test fmt::fmt-header-only)
|
||||
endif ()
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
*/
|
||||
|
||||
#define FMT_NOEXCEPT
|
||||
#undef FMT_SHARED
|
||||
#include "test-assert.h"
|
||||
|
||||
// Include format.cc instead of format.h to test implementation-specific stuff.
|
||||
// Include *.cc instead of *.h to test implementation-specific stuff.
|
||||
#include "fmt/format.cc"
|
||||
#include "fmt/printf.cc"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@@ -46,7 +48,7 @@ TEST(FormatTest, ArgConverter) {
|
||||
Arg arg = Arg();
|
||||
arg.type = Arg::LONG_LONG;
|
||||
arg.long_long_value = std::numeric_limits<fmt::LongLong>::max();
|
||||
fmt::ArgConverter<fmt::LongLong>(arg, 'd').visit(arg);
|
||||
fmt::internal::ArgConverter<fmt::LongLong>(arg, 'd').visit(arg);
|
||||
EXPECT_EQ(Arg::LONG_LONG, arg.type);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,23 @@
|
||||
// Test that the library compiles if None is defined to 0 as done by xlib.h.
|
||||
#define None 0
|
||||
|
||||
struct LocaleMock {
|
||||
static LocaleMock *instance;
|
||||
|
||||
MOCK_METHOD0(localeconv, lconv *());
|
||||
} *LocaleMock::instance;
|
||||
|
||||
namespace fmt {
|
||||
namespace std {
|
||||
using namespace ::std;
|
||||
lconv *localeconv() {
|
||||
return LocaleMock::instance ?
|
||||
LocaleMock::instance->localeconv() : ::std::localeconv();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "fmt/time.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "mock-allocator.h"
|
||||
@@ -235,7 +250,7 @@ TEST(WriterTest, Allocator) {
|
||||
std::size_t size =
|
||||
static_cast<std::size_t>(1.5 * fmt::internal::INLINE_BUFFER_SIZE);
|
||||
std::vector<char> mem(size);
|
||||
EXPECT_CALL(alloc, allocate(size)).WillOnce(testing::Return(&mem[0]));
|
||||
EXPECT_CALL(alloc, allocate(size, 0)).WillOnce(testing::Return(&mem[0]));
|
||||
for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE + 1; ++i)
|
||||
w << '*';
|
||||
EXPECT_CALL(alloc, deallocate(&mem[0], size));
|
||||
@@ -917,7 +932,7 @@ TEST(FormatterTest, RuntimeWidth) {
|
||||
FormatError, "number is too big");
|
||||
EXPECT_THROW_MSG(format("{0:{1}}", 0, -1l),
|
||||
FormatError, "negative width");
|
||||
if (fmt::internal::check(sizeof(long) > sizeof(int))) {
|
||||
if (fmt::internal::const_check(sizeof(long) > sizeof(int))) {
|
||||
long value = INT_MAX;
|
||||
EXPECT_THROW_MSG(format("{0:{1}}", 0, (value + 1)),
|
||||
FormatError, "number is too big");
|
||||
@@ -1036,7 +1051,7 @@ TEST(FormatterTest, RuntimePrecision) {
|
||||
FormatError, "number is too big");
|
||||
EXPECT_THROW_MSG(format("{0:.{1}}", 0, -1l),
|
||||
FormatError, "negative precision");
|
||||
if (fmt::internal::check(sizeof(long) > sizeof(int))) {
|
||||
if (fmt::internal::const_check(sizeof(long) > sizeof(int))) {
|
||||
long value = INT_MAX;
|
||||
EXPECT_THROW_MSG(format("{0:.{1}}", 0, (value + 1)),
|
||||
FormatError, "number is too big");
|
||||
@@ -1209,13 +1224,24 @@ TEST(FormatterTest, FormatOct) {
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatIntLocale) {
|
||||
#ifndef _WIN32
|
||||
const char *locale = "en_US.utf-8";
|
||||
#else
|
||||
const char *locale = "English_United States";
|
||||
#endif
|
||||
std::setlocale(LC_ALL, locale);
|
||||
EXPECT_EQ("1,234,567", format("{:n}", 1234567));
|
||||
ScopedMock<LocaleMock> mock;
|
||||
lconv lc = lconv();
|
||||
char sep[] = "--";
|
||||
lc.thousands_sep = sep;
|
||||
EXPECT_CALL(mock, localeconv()).Times(3).WillRepeatedly(testing::Return(&lc));
|
||||
EXPECT_EQ("123", format("{:n}", 123));
|
||||
EXPECT_EQ("1--234", format("{:n}", 1234));
|
||||
EXPECT_EQ("1--234--567", format("{:n}", 1234567));
|
||||
}
|
||||
|
||||
struct ConvertibleToLongLong {
|
||||
operator fmt::LongLong() const {
|
||||
return fmt::LongLong(1) << 32;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(FormatterTest, FormatConvertibleToLongLong) {
|
||||
EXPECT_EQ("100000000", format("{:x}", ConvertibleToLongLong()));
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatFloat) {
|
||||
@@ -1327,6 +1353,8 @@ TEST(FormatterTest, FormatUCharString) {
|
||||
EXPECT_EQ("test", format("{0:s}", str));
|
||||
const unsigned char *const_str = str;
|
||||
EXPECT_EQ("test", format("{0:s}", const_str));
|
||||
unsigned char *ptr = str;
|
||||
EXPECT_EQ("test", format("{0:s}", ptr));
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatPointer) {
|
||||
@@ -1350,7 +1378,7 @@ TEST(FormatterTest, FormatCStringRef) {
|
||||
EXPECT_EQ("test", format("{0}", CStringRef("test")));
|
||||
}
|
||||
|
||||
void format(fmt::BasicFormatter<char> &f, const char *, const Date &d) {
|
||||
void format_arg(fmt::BasicFormatter<char> &f, const char *, const Date &d) {
|
||||
f.writer() << d.year() << '-' << d.month() << '-' << d.day();
|
||||
}
|
||||
|
||||
@@ -1363,7 +1391,7 @@ TEST(FormatterTest, FormatCustom) {
|
||||
class Answer {};
|
||||
|
||||
template <typename Char>
|
||||
void format(fmt::BasicFormatter<Char> &f, const Char *, Answer) {
|
||||
void format_arg(fmt::BasicFormatter<Char> &f, const Char *, Answer) {
|
||||
f.writer() << "42";
|
||||
}
|
||||
|
||||
@@ -1534,13 +1562,25 @@ TEST(FormatTest, Variadic) {
|
||||
EXPECT_EQ(L"abc1", format(L"{}c{}", L"ab", 1));
|
||||
}
|
||||
|
||||
TEST(FormatTest, Time) {
|
||||
std::tm tm = std::tm();
|
||||
tm.tm_year = 116;
|
||||
tm.tm_mon = 3;
|
||||
tm.tm_mday = 25;
|
||||
EXPECT_EQ("The date is 2016-04-25.",
|
||||
fmt::format("The date is {:%Y-%m-%d}.", tm));
|
||||
TEST(FormatTest, JoinArg) {
|
||||
using fmt::join;
|
||||
int v1[3] = { 1, 2, 3 };
|
||||
std::vector<float> v2;
|
||||
v2.push_back(1.2f);
|
||||
v2.push_back(3.4f);
|
||||
|
||||
EXPECT_EQ("(1, 2, 3)", format("({})", join(v1 + 0, v1 + 3, ", ")));
|
||||
EXPECT_EQ("(1)", format("({})", join(v1 + 0, v1 + 1, ", ")));
|
||||
EXPECT_EQ("()", format("({})", join(v1 + 0, v1 + 0, ", ")));
|
||||
EXPECT_EQ("(001, 002, 003)", format("({:03})", join(v1 + 0, v1 + 3, ", ")));
|
||||
EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2.begin(), v2.end(), ", ")));
|
||||
|
||||
EXPECT_EQ(L"(1, 2, 3)", format(L"({})", join(v1 + 0, v1 + 3, L", ")));
|
||||
|
||||
#if FMT_HAS_GXX_CXX11
|
||||
EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, ", ")));
|
||||
EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2, ", ")));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -1644,3 +1684,10 @@ FMT_VARIADIC(void, custom_format, const char *)
|
||||
TEST(FormatTest, CustomArgFormatter) {
|
||||
custom_format("{}", 42);
|
||||
}
|
||||
|
||||
void convert(int);
|
||||
|
||||
// Check if there is no collision with convert function in the global namespace.
|
||||
TEST(FormatTest, ConvertCollision) {
|
||||
fmt::format("{}", 42);
|
||||
}
|
||||
|
||||
@@ -10090,8 +10090,9 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
|
||||
// threads concurrently.
|
||||
Result InvokeWith(const ArgumentTuple& args)
|
||||
GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
|
||||
return static_cast<const ResultHolder*>(
|
||||
this->UntypedInvokeWith(&args))->GetValueAndDelete();
|
||||
const ResultHolder *rh = static_cast<const ResultHolder*>(
|
||||
this->UntypedInvokeWith(&args));
|
||||
return rh ? rh->GetValueAndDelete() : Result();
|
||||
}
|
||||
|
||||
// Adds and returns a default action spec for this mock function.
|
||||
|
||||
@@ -320,7 +320,7 @@ TEST(StreamingAssertionsTest, EXPECT_WRITE) {
|
||||
|
||||
TEST(UtilTest, FormatSystemError) {
|
||||
fmt::MemoryWriter out;
|
||||
fmt::internal::format_system_error(out, EDOM, "test message");
|
||||
fmt::format_system_error(out, EDOM, "test message");
|
||||
EXPECT_EQ(out.str(), format_system_error(EDOM, "test message"));
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,6 @@ std::string read(File &f, std::size_t count) {
|
||||
|
||||
std::string format_system_error(int error_code, fmt::StringRef message) {
|
||||
fmt::MemoryWriter out;
|
||||
fmt::internal::format_system_error(out, error_code, message);
|
||||
fmt::format_system_error(out, error_code, message);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#define FMT_GTEST_EXTRA_H_
|
||||
|
||||
#include <string>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
@@ -172,4 +172,10 @@ std::string read(fmt::File &f, std::size_t count);
|
||||
|
||||
#endif // FMT_USE_FILE_DESCRIPTORS
|
||||
|
||||
template <typename Mock>
|
||||
struct ScopedMock : testing::StrictMock<Mock> {
|
||||
ScopedMock() { Mock::instance = this; }
|
||||
~ScopedMock() { Mock::instance = 0; }
|
||||
};
|
||||
|
||||
#endif // FMT_GTEST_EXTRA_H_
|
||||
|
||||
@@ -2823,7 +2823,11 @@ inline int IsATTY(int /* fd */) { return 0; }
|
||||
inline int IsATTY(int fd) { return _isatty(fd); }
|
||||
# endif // GTEST_OS_WINDOWS_MOBILE
|
||||
inline int StrCaseCmp(const char* s1, const char* s2) {
|
||||
return _stricmp(s1, s2);
|
||||
# if _EMULATE_GLIBC
|
||||
return strcasecmp(s1, s2);
|
||||
# else
|
||||
return _stricmp(s1, s2);
|
||||
# endif
|
||||
}
|
||||
inline char* StrDup(const char* src) { return _strdup(src); }
|
||||
# endif // __BORLANDC__
|
||||
|
||||
@@ -36,8 +36,8 @@ class MockAllocator {
|
||||
MockAllocator() {}
|
||||
MockAllocator(const MockAllocator &) {}
|
||||
typedef T value_type;
|
||||
MOCK_METHOD1_T(allocate, T* (std::size_t n));
|
||||
MOCK_METHOD2_T(deallocate, void (T* p, std::size_t n));
|
||||
MOCK_METHOD2_T(allocate, T *(std::size_t n, const T *h));
|
||||
MOCK_METHOD2_T(deallocate, void (T *p, std::size_t n));
|
||||
};
|
||||
|
||||
template <typename Allocator>
|
||||
@@ -78,8 +78,10 @@ class AllocatorRef {
|
||||
|
||||
Allocator *get() const { return alloc_; }
|
||||
|
||||
value_type* allocate(std::size_t n) { return alloc_->allocate(n); }
|
||||
void deallocate(value_type* p, std::size_t n) { alloc_->deallocate(p, n); }
|
||||
value_type *allocate(std::size_t n, const value_type *h) {
|
||||
return alloc_->allocate(n, h);
|
||||
}
|
||||
void deallocate(value_type *p, std::size_t n) { alloc_->deallocate(p, n); }
|
||||
};
|
||||
|
||||
#endif // FMT_MOCK_ALLOCATOR_H_
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "fmt/ostream.cc"
|
||||
#include "fmt/ostream.h"
|
||||
|
||||
#include <sstream>
|
||||
#include "gmock/gmock.h"
|
||||
@@ -35,13 +35,6 @@
|
||||
using fmt::format;
|
||||
using fmt::FormatError;
|
||||
|
||||
template <typename Char>
|
||||
std::basic_ostream<Char> &operator<<(
|
||||
std::basic_ostream<Char> &os, const BasicTestString<Char> &s) {
|
||||
os << s.value();
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const Date &d) {
|
||||
os << d.year() << '-' << d.month() << '-' << d.day();
|
||||
return os;
|
||||
@@ -128,22 +121,11 @@ TEST(OStreamTest, Print) {
|
||||
EXPECT_EQ("Don't panic!", os.str());
|
||||
}
|
||||
|
||||
TEST(OStreamTest, PrintfCustom) {
|
||||
EXPECT_EQ("abc", fmt::sprintf("%s", TestString("abc")));
|
||||
}
|
||||
|
||||
TEST(OStreamTest, FPrintf) {
|
||||
std::ostringstream os;
|
||||
int ret = fmt::fprintf(os, "Don't %s!", "panic");
|
||||
EXPECT_EQ("Don't panic!", os.str());
|
||||
EXPECT_EQ(12, ret);
|
||||
}
|
||||
|
||||
TEST(OStreamTest, WriteToOStream) {
|
||||
std::ostringstream os;
|
||||
fmt::MemoryWriter w;
|
||||
w << "foo";
|
||||
fmt::write(os, w);
|
||||
fmt::internal::write(os, w);
|
||||
EXPECT_EQ("foo", os.str());
|
||||
}
|
||||
|
||||
@@ -188,5 +170,5 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
|
||||
data += n;
|
||||
size -= static_cast<std::size_t>(n);
|
||||
} while (size != 0);
|
||||
fmt::write(os, w);
|
||||
fmt::internal::write(os, w);
|
||||
}
|
||||
|
||||
@@ -453,12 +453,6 @@ TEST(BufferedFileTest, FilenoNoRetry) {
|
||||
fileno_count = 0;
|
||||
}
|
||||
|
||||
template <typename Mock>
|
||||
struct ScopedMock : testing::StrictMock<Mock> {
|
||||
ScopedMock() { Mock::instance = this; }
|
||||
~ScopedMock() { Mock::instance = 0; }
|
||||
};
|
||||
|
||||
struct TestMock {
|
||||
static TestMock *instance;
|
||||
} *TestMock::instance;
|
||||
@@ -508,7 +502,7 @@ LocaleType newlocale(int category_mask, const char *locale, LocaleType base) {
|
||||
return LocaleMock::instance->newlocale(category_mask, locale, base);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
typedef int FreeLocaleResult;
|
||||
#else
|
||||
typedef void FreeLocaleResult;
|
||||
|
||||
@@ -232,7 +232,7 @@ TEST(FileTest, MoveAssignmentClosesFile) {
|
||||
File OpenBufferedFile(int &fd) {
|
||||
File f = open_file();
|
||||
fd = f.descriptor();
|
||||
return std::move(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
TEST(FileTest, MoveFromTemporaryInCtor) {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
|
||||
#include "fmt/printf.h"
|
||||
#include "fmt/format.h"
|
||||
#include "gtest-extra.h"
|
||||
#include "util.h"
|
||||
@@ -201,6 +202,8 @@ TEST(PrintfTest, HashFlag) {
|
||||
|
||||
TEST(PrintfTest, Width) {
|
||||
EXPECT_PRINTF(" abc", "%5s", "abc");
|
||||
EXPECT_PRINTF(" -42", "%5s", "-42");
|
||||
EXPECT_PRINTF(" 0.123456", "%10s", 0.123456);
|
||||
|
||||
// Width cannot be specified twice.
|
||||
EXPECT_THROW_MSG(fmt::sprintf("%5-5d", 42), FormatError,
|
||||
@@ -295,12 +298,13 @@ void TestLength(const char *length_spec, U value) {
|
||||
fmt::LongLong signed_value = 0;
|
||||
fmt::ULongLong unsigned_value = 0;
|
||||
// Apply integer promotion to the argument.
|
||||
fmt::ULongLong max = std::numeric_limits<U>::max();
|
||||
using fmt::internal::check;
|
||||
if (check(max <= static_cast<unsigned>(std::numeric_limits<int>::max()))) {
|
||||
using std::numeric_limits;
|
||||
fmt::ULongLong max = numeric_limits<U>::max();
|
||||
using fmt::internal::const_check;
|
||||
if (const_check(max <= static_cast<unsigned>(numeric_limits<int>::max()))) {
|
||||
signed_value = static_cast<int>(value);
|
||||
unsigned_value = static_cast<unsigned>(value);
|
||||
} else if (check(max <= std::numeric_limits<unsigned>::max())) {
|
||||
} else if (const_check(max <= numeric_limits<unsigned>::max())) {
|
||||
signed_value = static_cast<unsigned>(value);
|
||||
unsigned_value = static_cast<unsigned>(value);
|
||||
}
|
||||
@@ -379,11 +383,13 @@ TEST(PrintfTest, Bool) {
|
||||
TEST(PrintfTest, Int) {
|
||||
EXPECT_PRINTF("-42", "%d", -42);
|
||||
EXPECT_PRINTF("-42", "%i", -42);
|
||||
EXPECT_PRINTF("-42", "%s", -42);
|
||||
unsigned u = 0 - 42u;
|
||||
EXPECT_PRINTF(fmt::format("{}", u), "%u", -42);
|
||||
EXPECT_PRINTF(fmt::format("{:o}", u), "%o", -42);
|
||||
EXPECT_PRINTF(fmt::format("{:x}", u), "%x", -42);
|
||||
EXPECT_PRINTF(fmt::format("{:X}", u), "%X", -42);
|
||||
EXPECT_PRINTF(fmt::format("{}", u), "%s", u);
|
||||
}
|
||||
|
||||
TEST(PrintfTest, LongLong) {
|
||||
@@ -395,7 +401,11 @@ TEST(PrintfTest, LongLong) {
|
||||
|
||||
TEST(PrintfTest, Float) {
|
||||
EXPECT_PRINTF("392.650000", "%f", 392.65);
|
||||
EXPECT_PRINTF("392.65", "%.2f", 392.65);
|
||||
EXPECT_PRINTF("392.6", "%.1f", 392.65);
|
||||
EXPECT_PRINTF("393", "%.f", 392.65);
|
||||
EXPECT_PRINTF("392.650000", "%F", 392.65);
|
||||
EXPECT_PRINTF("392.65", "%s", 392.65);
|
||||
char buffer[BUFFER_SIZE];
|
||||
safe_sprintf(buffer, "%e", 392.65);
|
||||
EXPECT_PRINTF(buffer, "%e", 392.65);
|
||||
@@ -420,6 +430,7 @@ TEST(PrintfTest, Inf) {
|
||||
|
||||
TEST(PrintfTest, Char) {
|
||||
EXPECT_PRINTF("x", "%c", 'x');
|
||||
EXPECT_PRINTF("x", "%s", 'x');
|
||||
int max = std::numeric_limits<int>::max();
|
||||
EXPECT_PRINTF(fmt::format("{}", static_cast<char>(max)), "%c", max);
|
||||
//EXPECT_PRINTF("x", "%lc", L'x');
|
||||
@@ -438,13 +449,17 @@ TEST(PrintfTest, Pointer) {
|
||||
int n;
|
||||
void *p = &n;
|
||||
EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
|
||||
EXPECT_PRINTF(fmt::format("{}", p), "%s", p);
|
||||
p = 0;
|
||||
EXPECT_PRINTF("(nil)", "%p", p);
|
||||
EXPECT_PRINTF(" (nil)", "%10p", p);
|
||||
EXPECT_PRINTF("(nil)", "%s", p);
|
||||
EXPECT_PRINTF(" (nil)", "%10s", p);
|
||||
const char *s = "test";
|
||||
EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s);
|
||||
const char *null_str = 0;
|
||||
EXPECT_PRINTF("(nil)", "%p", null_str);
|
||||
EXPECT_PRINTF("(null)", "%s", null_str);
|
||||
}
|
||||
|
||||
TEST(PrintfTest, Location) {
|
||||
@@ -477,3 +492,20 @@ TEST(PrintfTest, PrintfError) {
|
||||
TEST(PrintfTest, WideString) {
|
||||
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc"));
|
||||
}
|
||||
|
||||
TEST(PrintfTest, PrintfCustom) {
|
||||
EXPECT_EQ("abc", fmt::sprintf("%s", TestString("abc")));
|
||||
}
|
||||
|
||||
TEST(PrintfTest, OStream) {
|
||||
std::ostringstream os;
|
||||
int ret = fmt::fprintf(os, "Don't %s!", "panic");
|
||||
EXPECT_EQ("Don't panic!", os.str());
|
||||
EXPECT_EQ(12, ret);
|
||||
}
|
||||
|
||||
TEST(PrintfTest, Writer) {
|
||||
fmt::MemoryWriter writer;
|
||||
printf(writer, "%d", 42);
|
||||
EXPECT_EQ("42", writer.str());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
Tests of string utilities
|
||||
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
|
||||
#include "fmt/string.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using fmt::internal::StringBuffer;
|
||||
|
||||
TEST(StringBufferTest, Empty) {
|
||||
StringBuffer<char> buffer;
|
||||
EXPECT_EQ(0u, buffer.size());
|
||||
EXPECT_EQ(0u, buffer.capacity());
|
||||
std::string data;
|
||||
// std::string may have initial capacity.
|
||||
std::size_t capacity = data.capacity();
|
||||
buffer.move_to(data);
|
||||
EXPECT_EQ("", data);
|
||||
EXPECT_EQ(capacity, data.capacity());
|
||||
}
|
||||
|
||||
TEST(StringBufferTest, Reserve) {
|
||||
StringBuffer<char> buffer;
|
||||
std::size_t capacity = std::string().capacity() + 10;
|
||||
buffer.reserve(capacity);
|
||||
EXPECT_EQ(0u, buffer.size());
|
||||
EXPECT_EQ(capacity, buffer.capacity());
|
||||
std::string data;
|
||||
buffer.move_to(data);
|
||||
EXPECT_EQ("", data);
|
||||
}
|
||||
|
||||
TEST(StringBufferTest, Resize) {
|
||||
StringBuffer<char> buffer;
|
||||
std::size_t size = std::string().capacity() + 10;
|
||||
buffer.resize(size);
|
||||
EXPECT_EQ(size, buffer.size());
|
||||
EXPECT_EQ(size, buffer.capacity());
|
||||
std::string data;
|
||||
buffer.move_to(data);
|
||||
EXPECT_EQ(size, data.size());
|
||||
}
|
||||
|
||||
TEST(StringBufferTest, MoveTo) {
|
||||
StringBuffer<char> buffer;
|
||||
std::size_t size = std::string().capacity() + 10;
|
||||
buffer.resize(size);
|
||||
const char *p = &buffer[0];
|
||||
std::string data;
|
||||
buffer.move_to(data);
|
||||
EXPECT_EQ(p, &data[0]);
|
||||
EXPECT_EQ(0u, buffer.size());
|
||||
EXPECT_EQ(0u, buffer.capacity());
|
||||
}
|
||||
|
||||
TEST(StringWriterTest, MoveTo) {
|
||||
fmt::StringWriter out;
|
||||
out << "The answer is " << 42 << "\n";
|
||||
std::string s;
|
||||
out.move_to(s);
|
||||
EXPECT_EQ("The answer is 42\n", s);
|
||||
EXPECT_EQ(0u, out.size());
|
||||
}
|
||||
|
||||
TEST(StringWriterTest, WString) {
|
||||
fmt::WStringWriter out;
|
||||
out << "The answer is " << 42 << "\n";
|
||||
std::wstring s;
|
||||
out.move_to(s);
|
||||
EXPECT_EQ(L"The answer is 42\n", s);
|
||||
}
|
||||
|
||||
TEST(StringTest, ToString) {
|
||||
EXPECT_EQ("42", fmt::to_string(42));
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Time formatting tests
|
||||
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
For the license information refer to format.h.
|
||||
*/
|
||||
#ifdef WIN32
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "fmt/time.h"
|
||||
|
||||
TEST(TimeTest, Format) {
|
||||
std::tm tm = std::tm();
|
||||
tm.tm_year = 116;
|
||||
tm.tm_mon = 3;
|
||||
tm.tm_mday = 25;
|
||||
EXPECT_EQ("The date is 2016-04-25.",
|
||||
fmt::format("The date is {:%Y-%m-%d}.", tm));
|
||||
}
|
||||
|
||||
TEST(TimeTest, GrowBuffer) {
|
||||
std::string s = "{:";
|
||||
for (int i = 0; i < 30; ++i)
|
||||
s += "%c";
|
||||
s += "}\n";
|
||||
std::time_t t = std::time(0);
|
||||
fmt::format(s, *std::localtime(&t));
|
||||
}
|
||||
|
||||
TEST(TimeTest, EmptyResult) {
|
||||
EXPECT_EQ("", fmt::format("{}", std::tm()));
|
||||
}
|
||||
|
||||
bool EqualTime(const std::tm &lhs, const std::tm &rhs) {
|
||||
return lhs.tm_sec == rhs.tm_sec &&
|
||||
lhs.tm_min == rhs.tm_min &&
|
||||
lhs.tm_hour == rhs.tm_hour &&
|
||||
lhs.tm_mday == rhs.tm_mday &&
|
||||
lhs.tm_mon == rhs.tm_mon &&
|
||||
lhs.tm_year == rhs.tm_year &&
|
||||
lhs.tm_wday == rhs.tm_wday &&
|
||||
lhs.tm_yday == rhs.tm_yday &&
|
||||
lhs.tm_isdst == rhs.tm_isdst;
|
||||
}
|
||||
|
||||
TEST(TimeTest, LocalTime) {
|
||||
std::time_t t = std::time(0);
|
||||
std::tm tm = *std::localtime(&t);
|
||||
EXPECT_TRUE(EqualTime(tm, fmt::localtime(t)));
|
||||
}
|
||||
|
||||
TEST(TimeTest, GMTime) {
|
||||
std::time_t t = std::time(0);
|
||||
std::tm tm = *std::gmtime(&t);
|
||||
EXPECT_TRUE(EqualTime(tm, fmt::gmtime(t)));
|
||||
}
|
||||
@@ -64,7 +64,7 @@ namespace {
|
||||
struct Test {};
|
||||
|
||||
template <typename Char>
|
||||
void format(fmt::BasicFormatter<Char> &f, const Char *, Test) {
|
||||
void format_arg(fmt::BasicFormatter<Char> &f, const Char *, Test) {
|
||||
f.writer() << "test";
|
||||
}
|
||||
|
||||
@@ -83,8 +83,8 @@ void CheckForwarding(
|
||||
// Check if value_type is properly defined.
|
||||
AllocatorRef< MockAllocator<int> >::value_type *ptr = &mem;
|
||||
// Check forwarding.
|
||||
EXPECT_CALL(alloc, allocate(42)).WillOnce(Return(ptr));
|
||||
ref.allocate(42);
|
||||
EXPECT_CALL(alloc, allocate(42, 0)).WillOnce(Return(ptr));
|
||||
ref.allocate(42, 0);
|
||||
EXPECT_CALL(alloc, deallocate(ptr, 42));
|
||||
ref.deallocate(ptr, 42);
|
||||
}
|
||||
@@ -339,7 +339,7 @@ TEST(MemoryBufferTest, Grow) {
|
||||
EXPECT_EQ(10u, buffer.capacity());
|
||||
int mem[20];
|
||||
mem[7] = 0xdead;
|
||||
EXPECT_CALL(alloc, allocate(20)).WillOnce(Return(mem));
|
||||
EXPECT_CALL(alloc, allocate(20, 0)).WillOnce(Return(mem));
|
||||
buffer.grow(20);
|
||||
EXPECT_EQ(20u, buffer.capacity());
|
||||
// Check if size elements have been copied
|
||||
@@ -360,7 +360,7 @@ TEST(MemoryBufferTest, Allocator) {
|
||||
MemoryBuffer<char, 10, TestAllocator> buffer2((TestAllocator(&alloc)));
|
||||
EXPECT_EQ(&alloc, buffer2.get_allocator().get());
|
||||
std::size_t size = 2 * fmt::internal::INLINE_BUFFER_SIZE;
|
||||
EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem));
|
||||
EXPECT_CALL(alloc, allocate(size, 0)).WillOnce(Return(&mem));
|
||||
buffer2.reserve(size);
|
||||
EXPECT_CALL(alloc, deallocate(&mem, size));
|
||||
}
|
||||
@@ -373,13 +373,13 @@ TEST(MemoryBufferTest, ExceptionInDeallocate) {
|
||||
std::size_t size = 2 * fmt::internal::INLINE_BUFFER_SIZE;
|
||||
std::vector<char> mem(size);
|
||||
{
|
||||
EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem[0]));
|
||||
EXPECT_CALL(alloc, allocate(size, 0)).WillOnce(Return(&mem[0]));
|
||||
buffer.resize(size);
|
||||
std::fill(&buffer[0], &buffer[0] + size, 'x');
|
||||
}
|
||||
std::vector<char> mem2(2 * size);
|
||||
{
|
||||
EXPECT_CALL(alloc, allocate(2 * size)).WillOnce(Return(&mem2[0]));
|
||||
EXPECT_CALL(alloc, allocate(2 * size, 0)).WillOnce(Return(&mem2[0]));
|
||||
std::exception e;
|
||||
EXPECT_CALL(alloc, deallocate(&mem[0], size)).WillOnce(testing::Throw(e));
|
||||
EXPECT_THROW(buffer.reserve(2 * size), std::exception);
|
||||
@@ -581,7 +581,7 @@ struct CustomFormatter {
|
||||
typedef char Char;
|
||||
};
|
||||
|
||||
void format(CustomFormatter &, const char *&s, const Test &) {
|
||||
void format_arg(CustomFormatter &, const char *&s, const Test &) {
|
||||
s = "custom_format";
|
||||
}
|
||||
|
||||
@@ -708,7 +708,7 @@ TEST(ArgVisitorTest, VisitUnhandledArg) {
|
||||
|
||||
TEST(ArgVisitorTest, VisitInvalidArg) {
|
||||
Arg arg = Arg();
|
||||
arg.type = static_cast<Arg::Type>(Arg::CUSTOM + 1);
|
||||
arg.type = static_cast<Arg::Type>(Arg::NONE);
|
||||
EXPECT_ASSERT(TestVisitor().visit(arg), "invalid argument type");
|
||||
}
|
||||
|
||||
@@ -834,10 +834,10 @@ void check_throw_error(int error_code, FormatErrorMessage format) {
|
||||
|
||||
TEST(UtilTest, FormatSystemError) {
|
||||
fmt::MemoryWriter message;
|
||||
fmt::internal::format_system_error(message, EDOM, "test");
|
||||
fmt::format_system_error(message, EDOM, "test");
|
||||
EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), message.str());
|
||||
message.clear();
|
||||
fmt::internal::format_system_error(
|
||||
fmt::format_system_error(
|
||||
message, EDOM, fmt::StringRef(0, std::numeric_limits<size_t>::max()));
|
||||
EXPECT_EQ(fmt::format("error {}", EDOM), message.str());
|
||||
}
|
||||
@@ -846,12 +846,12 @@ TEST(UtilTest, SystemError) {
|
||||
fmt::SystemError e(EDOM, "test");
|
||||
EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), e.what());
|
||||
EXPECT_EQ(EDOM, e.error_code());
|
||||
check_throw_error<fmt::SystemError>(EDOM, fmt::internal::format_system_error);
|
||||
check_throw_error<fmt::SystemError>(EDOM, fmt::format_system_error);
|
||||
}
|
||||
|
||||
TEST(UtilTest, ReportSystemError) {
|
||||
fmt::MemoryWriter out;
|
||||
fmt::internal::format_system_error(out, EDOM, "test error");
|
||||
fmt::format_system_error(out, EDOM, "test error");
|
||||
out << '\n';
|
||||
EXPECT_WRITE(stderr, fmt::report_system_error(EDOM, "test error"), out.str());
|
||||
}
|
||||
@@ -956,3 +956,17 @@ TEST(UtilTest, Conditional) {
|
||||
fmt::internal::Conditional<false, int, char>::type *pc = &c;
|
||||
(void)pc;
|
||||
}
|
||||
|
||||
struct TestLConv {
|
||||
char *thousands_sep;
|
||||
};
|
||||
|
||||
struct EmptyLConv {};
|
||||
|
||||
TEST(UtilTest, ThousandsSep) {
|
||||
char foo[] = "foo";
|
||||
TestLConv lc = {foo};
|
||||
EXPECT_EQ("foo", fmt::internal::thousands_sep(&lc).to_string());
|
||||
EmptyLConv empty_lc;
|
||||
EXPECT_EQ("", fmt::internal::thousands_sep(&empty_lc));
|
||||
}
|
||||
|
||||
@@ -87,6 +87,13 @@ const Char BasicTestString<Char>::EMPTY[] = {0};
|
||||
typedef BasicTestString<char> TestString;
|
||||
typedef BasicTestString<wchar_t> TestWString;
|
||||
|
||||
template <typename Char>
|
||||
std::basic_ostream<Char> &operator<<(
|
||||
std::basic_ostream<Char> &os, const BasicTestString<Char> &s) {
|
||||
os << s.value();
|
||||
return os;
|
||||
}
|
||||
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
public:
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
|
||||
SET(recast_navigation_sources
|
||||
detour/src/DetourAlloc.cpp
|
||||
detour/src/DetourAssert.cpp
|
||||
detour/src/DetourCommon.cpp
|
||||
detour/src/DetourNavMesh.cpp
|
||||
detour/src/DetourNavMeshBuilder.cpp
|
||||
detour/src/DetourNavMeshQuery.cpp
|
||||
detour/src/DetourNode.cpp
|
||||
recast/src/Recast.cpp
|
||||
recast/src/RecastAlloc.cpp
|
||||
recast/src/RecastArea.cpp
|
||||
recast/src/RecastAssert.cpp
|
||||
recast/src/RecastContour.cpp
|
||||
recast/src/RecastFilter.cpp
|
||||
recast/src/RecastLayers.cpp
|
||||
recast/src/RecastMesh.cpp
|
||||
recast/src/RecastMeshDetail.cpp
|
||||
recast/src/RecastRasterization.cpp
|
||||
recast/src/RecastRegion.cpp
|
||||
)
|
||||
|
||||
SET(recast_navigation_headers
|
||||
detour/include/DetourAlloc.h
|
||||
detour/include/DetourAssert.h
|
||||
detour/include/DetourCommon.h
|
||||
detour/include/DetourMath.h
|
||||
detour/include/DetourNavMesh.h
|
||||
detour/include/DetourNavMeshBuilder.h
|
||||
detour/include/DetourNavMeshQuery.h
|
||||
detour/include/DetourNode.h
|
||||
detour/include/DetourStatus.h
|
||||
recast/include/Recast.h
|
||||
recast/include/RecastAlloc.h
|
||||
recast/include/RecastAssert.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Detour FILES
|
||||
detour/src/DetourAlloc.cpp
|
||||
detour/src/DetourAssert.cpp
|
||||
detour/src/DetourCommon.cpp
|
||||
detour/src/DetourNavMesh.cpp
|
||||
detour/src/DetourNavMeshBuilder.cpp
|
||||
detour/src/DetourNavMeshQuery.cpp
|
||||
detour/src/DetourNode.cpp
|
||||
detour/include/DetourAlloc.h
|
||||
detour/include/DetourAssert.h
|
||||
detour/include/DetourCommon.h
|
||||
detour/include/DetourMath.h
|
||||
detour/include/DetourNavMesh.h
|
||||
detour/include/DetourNavMeshBuilder.h
|
||||
detour/include/DetourNavMeshQuery.h
|
||||
detour/include/DetourNode.h
|
||||
detour/include/DetourStatus.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Recast FILES
|
||||
recast/src/Recast.cpp
|
||||
recast/src/RecastAlloc.cpp
|
||||
recast/src/RecastArea.cpp
|
||||
recast/src/RecastAssert.cpp
|
||||
recast/src/RecastContour.cpp
|
||||
recast/src/RecastFilter.cpp
|
||||
recast/src/RecastLayers.cpp
|
||||
recast/src/RecastMesh.cpp
|
||||
recast/src/RecastMeshDetail.cpp
|
||||
recast/src/RecastRasterization.cpp
|
||||
recast/src/RecastRegion.cpp
|
||||
recast/include/Recast.h
|
||||
recast/include/RecastAlloc.h
|
||||
recast/include/RecastAssert.h
|
||||
)
|
||||
|
||||
ADD_LIBRARY(recast_navigation ${recast_navigation_sources} ${recast_navigation_headers})
|
||||
|
||||
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
|
||||
@@ -0,0 +1,223 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef DEBUGDRAW_H
|
||||
#define DEBUGDRAW_H
|
||||
|
||||
// Some math headers don't have PI defined.
|
||||
static const float DU_PI = 3.14159265f;
|
||||
|
||||
enum duDebugDrawPrimitives
|
||||
{
|
||||
DU_DRAW_POINTS,
|
||||
DU_DRAW_LINES,
|
||||
DU_DRAW_TRIS,
|
||||
DU_DRAW_QUADS,
|
||||
};
|
||||
|
||||
/// Abstract debug draw interface.
|
||||
struct duDebugDraw
|
||||
{
|
||||
virtual ~duDebugDraw() = 0;
|
||||
|
||||
virtual void depthMask(bool state) = 0;
|
||||
|
||||
virtual void texture(bool state) = 0;
|
||||
|
||||
/// Begin drawing primitives.
|
||||
/// @param prim [in] primitive type to draw, one of rcDebugDrawPrimitives.
|
||||
/// @param size [in] size of a primitive, applies to point size and line width only.
|
||||
virtual void begin(duDebugDrawPrimitives prim, float size = 1.0f) = 0;
|
||||
|
||||
/// Submit a vertex
|
||||
/// @param pos [in] position of the verts.
|
||||
/// @param color [in] color of the verts.
|
||||
virtual void vertex(const float* pos, unsigned int color) = 0;
|
||||
|
||||
/// Submit a vertex
|
||||
/// @param x,y,z [in] position of the verts.
|
||||
/// @param color [in] color of the verts.
|
||||
virtual void vertex(const float x, const float y, const float z, unsigned int color) = 0;
|
||||
|
||||
/// Submit a vertex
|
||||
/// @param pos [in] position of the verts.
|
||||
/// @param color [in] color of the verts.
|
||||
virtual void vertex(const float* pos, unsigned int color, const float* uv) = 0;
|
||||
|
||||
/// Submit a vertex
|
||||
/// @param x,y,z [in] position of the verts.
|
||||
/// @param color [in] color of the verts.
|
||||
virtual void vertex(const float x, const float y, const float z, unsigned int color, const float u, const float v) = 0;
|
||||
|
||||
/// End drawing primitives.
|
||||
virtual void end() = 0;
|
||||
|
||||
/// Compute a color for given area.
|
||||
virtual unsigned int areaToCol(unsigned int area);
|
||||
};
|
||||
|
||||
inline unsigned int duRGBA(int r, int g, int b, int a)
|
||||
{
|
||||
return ((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24);
|
||||
}
|
||||
|
||||
inline unsigned int duRGBAf(float fr, float fg, float fb, float fa)
|
||||
{
|
||||
unsigned char r = (unsigned char)(fr*255.0f);
|
||||
unsigned char g = (unsigned char)(fg*255.0f);
|
||||
unsigned char b = (unsigned char)(fb*255.0f);
|
||||
unsigned char a = (unsigned char)(fa*255.0f);
|
||||
return duRGBA(r,g,b,a);
|
||||
}
|
||||
|
||||
unsigned int duIntToCol(int i, int a);
|
||||
void duIntToCol(int i, float* col);
|
||||
|
||||
inline unsigned int duMultCol(const unsigned int col, const unsigned int d)
|
||||
{
|
||||
const unsigned int r = col & 0xff;
|
||||
const unsigned int g = (col >> 8) & 0xff;
|
||||
const unsigned int b = (col >> 16) & 0xff;
|
||||
const unsigned int a = (col >> 24) & 0xff;
|
||||
return duRGBA((r*d) >> 8, (g*d) >> 8, (b*d) >> 8, a);
|
||||
}
|
||||
|
||||
inline unsigned int duDarkenCol(unsigned int col)
|
||||
{
|
||||
return ((col >> 1) & 0x007f7f7f) | (col & 0xff000000);
|
||||
}
|
||||
|
||||
inline unsigned int duLerpCol(unsigned int ca, unsigned int cb, unsigned int u)
|
||||
{
|
||||
const unsigned int ra = ca & 0xff;
|
||||
const unsigned int ga = (ca >> 8) & 0xff;
|
||||
const unsigned int ba = (ca >> 16) & 0xff;
|
||||
const unsigned int aa = (ca >> 24) & 0xff;
|
||||
const unsigned int rb = cb & 0xff;
|
||||
const unsigned int gb = (cb >> 8) & 0xff;
|
||||
const unsigned int bb = (cb >> 16) & 0xff;
|
||||
const unsigned int ab = (cb >> 24) & 0xff;
|
||||
|
||||
unsigned int r = (ra*(255-u) + rb*u)/255;
|
||||
unsigned int g = (ga*(255-u) + gb*u)/255;
|
||||
unsigned int b = (ba*(255-u) + bb*u)/255;
|
||||
unsigned int a = (aa*(255-u) + ab*u)/255;
|
||||
return duRGBA(r,g,b,a);
|
||||
}
|
||||
|
||||
inline unsigned int duTransCol(unsigned int c, unsigned int a)
|
||||
{
|
||||
return (a<<24) | (c & 0x00ffffff);
|
||||
}
|
||||
|
||||
|
||||
void duCalcBoxColors(unsigned int* colors, unsigned int colTop, unsigned int colSide);
|
||||
|
||||
void duDebugDrawCylinderWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col, const float lineWidth);
|
||||
|
||||
void duDebugDrawBoxWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col, const float lineWidth);
|
||||
|
||||
void duDebugDrawArc(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1, const float h,
|
||||
const float as0, const float as1, unsigned int col, const float lineWidth);
|
||||
|
||||
void duDebugDrawArrow(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1,
|
||||
const float as0, const float as1, unsigned int col, const float lineWidth);
|
||||
|
||||
void duDebugDrawCircle(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float r, unsigned int col, const float lineWidth);
|
||||
|
||||
void duDebugDrawCross(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float size, unsigned int col, const float lineWidth);
|
||||
|
||||
void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, const unsigned int* fcol);
|
||||
|
||||
void duDebugDrawCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col);
|
||||
|
||||
void duDebugDrawGridXZ(struct duDebugDraw* dd, const float ox, const float oy, const float oz,
|
||||
const int w, const int h, const float size,
|
||||
const unsigned int col, const float lineWidth);
|
||||
|
||||
|
||||
// Versions without begin/end, can be used to draw multiple primitives.
|
||||
void duAppendCylinderWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col);
|
||||
|
||||
void duAppendBoxWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col);
|
||||
|
||||
void duAppendBoxPoints(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col);
|
||||
|
||||
void duAppendArc(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1, const float h,
|
||||
const float as0, const float as1, unsigned int col);
|
||||
|
||||
void duAppendArrow(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1,
|
||||
const float as0, const float as1, unsigned int col);
|
||||
|
||||
void duAppendCircle(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float r, unsigned int col);
|
||||
|
||||
void duAppendCross(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float size, unsigned int col);
|
||||
|
||||
void duAppendBox(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, const unsigned int* fcol);
|
||||
|
||||
void duAppendCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col);
|
||||
|
||||
|
||||
class duDisplayList : public duDebugDraw
|
||||
{
|
||||
float* m_pos;
|
||||
unsigned int* m_color;
|
||||
int m_size;
|
||||
int m_cap;
|
||||
|
||||
bool m_depthMask;
|
||||
duDebugDrawPrimitives m_prim;
|
||||
float m_primSize;
|
||||
|
||||
void resize(int cap);
|
||||
|
||||
public:
|
||||
duDisplayList(int cap = 512);
|
||||
~duDisplayList();
|
||||
virtual void depthMask(bool state);
|
||||
virtual void begin(duDebugDrawPrimitives prim, float size = 1.0f);
|
||||
virtual void vertex(const float x, const float y, const float z, unsigned int color);
|
||||
virtual void vertex(const float* pos, unsigned int color);
|
||||
virtual void end();
|
||||
void clear();
|
||||
void draw(struct duDebugDraw* dd);
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
duDisplayList(const duDisplayList&);
|
||||
duDisplayList& operator=(const duDisplayList&);
|
||||
};
|
||||
|
||||
|
||||
#endif // DEBUGDRAW_H
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef DETOURDEBUGDRAW_H
|
||||
#define DETOURDEBUGDRAW_H
|
||||
|
||||
#include "DetourNavMesh.h"
|
||||
#include "DetourNavMeshQuery.h"
|
||||
#include "DetourTileCacheBuilder.h"
|
||||
|
||||
enum DrawNavMeshFlags
|
||||
{
|
||||
DU_DRAWNAVMESH_OFFMESHCONS = 0x01,
|
||||
DU_DRAWNAVMESH_CLOSEDLIST = 0x02,
|
||||
DU_DRAWNAVMESH_COLOR_TILES = 0x04,
|
||||
};
|
||||
|
||||
void duDebugDrawNavMesh(struct duDebugDraw* dd, const dtNavMesh& mesh, unsigned char flags);
|
||||
void duDebugDrawNavMeshWithClosedList(struct duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery& query, unsigned char flags);
|
||||
void duDebugDrawNavMeshNodes(struct duDebugDraw* dd, const dtNavMeshQuery& query);
|
||||
void duDebugDrawNavMeshBVTree(struct duDebugDraw* dd, const dtNavMesh& mesh);
|
||||
void duDebugDrawNavMeshPortals(struct duDebugDraw* dd, const dtNavMesh& mesh);
|
||||
void duDebugDrawNavMeshPolysWithFlags(struct duDebugDraw* dd, const dtNavMesh& mesh, const unsigned short polyFlags, const unsigned int col);
|
||||
void duDebugDrawNavMeshPoly(struct duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col);
|
||||
|
||||
void duDebugDrawTileCacheLayerAreas(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch);
|
||||
void duDebugDrawTileCacheLayerRegions(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch);
|
||||
void duDebugDrawTileCacheContours(duDebugDraw* dd, const struct dtTileCacheContourSet& lcset,
|
||||
const float* orig, const float cs, const float ch);
|
||||
void duDebugDrawTileCachePolyMesh(duDebugDraw* dd, const struct dtTileCachePolyMesh& lmesh,
|
||||
const float* orig, const float cs, const float ch);
|
||||
|
||||
#endif // DETOURDEBUGDRAW_H
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef RECAST_DEBUGDRAW_H
|
||||
#define RECAST_DEBUGDRAW_H
|
||||
|
||||
void duDebugDrawTriMesh(struct duDebugDraw* dd, const float* verts, int nverts, const int* tris, const float* normals, int ntris, const unsigned char* flags, const float texScale);
|
||||
void duDebugDrawTriMeshSlope(struct duDebugDraw* dd, const float* verts, int nverts, const int* tris, const float* normals, int ntris, const float walkableSlopeAngle, const float texScale);
|
||||
|
||||
void duDebugDrawHeightfieldSolid(struct duDebugDraw* dd, const struct rcHeightfield& hf);
|
||||
void duDebugDrawHeightfieldWalkable(struct duDebugDraw* dd, const struct rcHeightfield& hf);
|
||||
|
||||
void duDebugDrawCompactHeightfieldSolid(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
|
||||
void duDebugDrawCompactHeightfieldRegions(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
|
||||
void duDebugDrawCompactHeightfieldDistance(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
|
||||
|
||||
void duDebugDrawHeightfieldLayer(duDebugDraw* dd, const struct rcHeightfieldLayer& layer, const int idx);
|
||||
void duDebugDrawHeightfieldLayers(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset);
|
||||
void duDebugDrawHeightfieldLayersRegions(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset);
|
||||
|
||||
void duDebugDrawRegionConnections(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
||||
void duDebugDrawRawContours(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
||||
void duDebugDrawContours(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
||||
void duDebugDrawPolyMesh(struct duDebugDraw* dd, const struct rcPolyMesh& mesh);
|
||||
void duDebugDrawPolyMeshDetail(struct duDebugDraw* dd, const struct rcPolyMeshDetail& dmesh);
|
||||
|
||||
#endif // RECAST_DEBUGDRAW_H
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef RECAST_DUMP_H
|
||||
#define RECAST_DUMP_H
|
||||
|
||||
struct duFileIO
|
||||
{
|
||||
virtual ~duFileIO() = 0;
|
||||
virtual bool isWriting() const = 0;
|
||||
virtual bool isReading() const = 0;
|
||||
virtual bool write(const void* ptr, const size_t size) = 0;
|
||||
virtual bool read(void* ptr, const size_t size) = 0;
|
||||
};
|
||||
|
||||
bool duDumpPolyMeshToObj(struct rcPolyMesh& pmesh, duFileIO* io);
|
||||
bool duDumpPolyMeshDetailToObj(struct rcPolyMeshDetail& dmesh, duFileIO* io);
|
||||
|
||||
bool duDumpContourSet(struct rcContourSet& cset, duFileIO* io);
|
||||
bool duReadContourSet(struct rcContourSet& cset, duFileIO* io);
|
||||
|
||||
bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io);
|
||||
bool duReadCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io);
|
||||
|
||||
void duLogBuildTimes(rcContext& ctx, const int totalTileUsec);
|
||||
|
||||
|
||||
#endif // RECAST_DUMP_H
|
||||
@@ -0,0 +1,612 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <string.h>
|
||||
#include "DebugDraw.h"
|
||||
#include "DetourMath.h"
|
||||
#include "DetourNavMesh.h"
|
||||
|
||||
|
||||
duDebugDraw::~duDebugDraw()
|
||||
{
|
||||
// Empty
|
||||
}
|
||||
|
||||
unsigned int duDebugDraw::areaToCol(unsigned int area)
|
||||
{
|
||||
if (area == 0)
|
||||
{
|
||||
// Treat zero area type as default.
|
||||
return duRGBA(0, 192, 255, 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
return duIntToCol(area, 255);
|
||||
}
|
||||
}
|
||||
|
||||
inline int bit(int a, int b)
|
||||
{
|
||||
return (a & (1 << b)) >> b;
|
||||
}
|
||||
|
||||
unsigned int duIntToCol(int i, int a)
|
||||
{
|
||||
int r = bit(i, 1) + bit(i, 3) * 2 + 1;
|
||||
int g = bit(i, 2) + bit(i, 4) * 2 + 1;
|
||||
int b = bit(i, 0) + bit(i, 5) * 2 + 1;
|
||||
return duRGBA(r*63,g*63,b*63,a);
|
||||
}
|
||||
|
||||
void duIntToCol(int i, float* col)
|
||||
{
|
||||
int r = bit(i, 0) + bit(i, 3) * 2 + 1;
|
||||
int g = bit(i, 1) + bit(i, 4) * 2 + 1;
|
||||
int b = bit(i, 2) + bit(i, 5) * 2 + 1;
|
||||
col[0] = 1 - r*63.0f/255.0f;
|
||||
col[1] = 1 - g*63.0f/255.0f;
|
||||
col[2] = 1 - b*63.0f/255.0f;
|
||||
}
|
||||
|
||||
void duCalcBoxColors(unsigned int* colors, unsigned int colTop, unsigned int colSide)
|
||||
{
|
||||
if (!colors) return;
|
||||
|
||||
colors[0] = duMultCol(colTop, 250);
|
||||
colors[1] = duMultCol(colSide, 140);
|
||||
colors[2] = duMultCol(colSide, 165);
|
||||
colors[3] = duMultCol(colSide, 217);
|
||||
colors[4] = duMultCol(colSide, 165);
|
||||
colors[5] = duMultCol(colSide, 217);
|
||||
}
|
||||
|
||||
void duDebugDrawCylinderWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendCylinderWire(dd, minx,miny,minz, maxx,maxy,maxz, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawBoxWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendBoxWire(dd, minx,miny,minz, maxx,maxy,maxz, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawArc(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1, const float h,
|
||||
const float as0, const float as1, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendArc(dd, x0,y0,z0, x1,y1,z1, h, as0, as1, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawArrow(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1,
|
||||
const float as0, const float as1, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendArrow(dd, x0,y0,z0, x1,y1,z1, as0, as1, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawCircle(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float r, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendCircle(dd, x,y,z, r, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawCross(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float size, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendCross(dd, x,y,z, size, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, const unsigned int* fcol)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_QUADS);
|
||||
duAppendBox(dd, minx,miny,minz, maxx,maxy,maxz, fcol);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_TRIS);
|
||||
duAppendCylinder(dd, minx,miny,minz, maxx,maxy,maxz, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawGridXZ(struct duDebugDraw* dd, const float ox, const float oy, const float oz,
|
||||
const int w, const int h, const float size,
|
||||
const unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
for (int i = 0; i <= h; ++i)
|
||||
{
|
||||
dd->vertex(ox,oy,oz+i*size, col);
|
||||
dd->vertex(ox+w*size,oy,oz+i*size, col);
|
||||
}
|
||||
for (int i = 0; i <= w; ++i)
|
||||
{
|
||||
dd->vertex(ox+i*size,oy,oz, col);
|
||||
dd->vertex(ox+i*size,oy,oz+h*size, col);
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
|
||||
void duAppendCylinderWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
static const int NUM_SEG = 16;
|
||||
static float dir[NUM_SEG*2];
|
||||
static bool init = false;
|
||||
if (!init)
|
||||
{
|
||||
init = true;
|
||||
for (int i = 0; i < NUM_SEG; ++i)
|
||||
{
|
||||
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
|
||||
dir[i*2] = dtMathCosf(a);
|
||||
dir[i*2+1] = dtMathSinf(a);
|
||||
}
|
||||
}
|
||||
|
||||
const float cx = (maxx + minx)/2;
|
||||
const float cz = (maxz + minz)/2;
|
||||
const float rx = (maxx - minx)/2;
|
||||
const float rz = (maxz - minz)/2;
|
||||
|
||||
for (int i = 0, j = NUM_SEG-1; i < NUM_SEG; j = i++)
|
||||
{
|
||||
dd->vertex(cx+dir[j*2+0]*rx, miny, cz+dir[j*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz, col);
|
||||
}
|
||||
for (int i = 0; i < NUM_SEG; i += NUM_SEG/4)
|
||||
{
|
||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz, col);
|
||||
}
|
||||
}
|
||||
|
||||
void duAppendBoxWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
// Top
|
||||
dd->vertex(minx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, maxz, col);
|
||||
dd->vertex(maxx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, minz, col);
|
||||
|
||||
// bottom
|
||||
dd->vertex(minx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, maxz, col);
|
||||
dd->vertex(maxx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, minz, col);
|
||||
|
||||
// Sides
|
||||
dd->vertex(minx, miny, minz, col);
|
||||
dd->vertex(minx, maxy, minz, col);
|
||||
dd->vertex(maxx, miny, minz, col);
|
||||
dd->vertex(maxx, maxy, minz, col);
|
||||
dd->vertex(maxx, miny, maxz, col);
|
||||
dd->vertex(maxx, maxy, maxz, col);
|
||||
dd->vertex(minx, miny, maxz, col);
|
||||
dd->vertex(minx, maxy, maxz, col);
|
||||
}
|
||||
|
||||
void duAppendBoxPoints(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
// Top
|
||||
dd->vertex(minx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, maxz, col);
|
||||
dd->vertex(maxx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, minz, col);
|
||||
|
||||
// bottom
|
||||
dd->vertex(minx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, maxz, col);
|
||||
dd->vertex(maxx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, minz, col);
|
||||
}
|
||||
|
||||
void duAppendBox(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, const unsigned int* fcol)
|
||||
{
|
||||
if (!dd) return;
|
||||
const float verts[8*3] =
|
||||
{
|
||||
minx, miny, minz,
|
||||
maxx, miny, minz,
|
||||
maxx, miny, maxz,
|
||||
minx, miny, maxz,
|
||||
minx, maxy, minz,
|
||||
maxx, maxy, minz,
|
||||
maxx, maxy, maxz,
|
||||
minx, maxy, maxz,
|
||||
};
|
||||
static const unsigned char inds[6*4] =
|
||||
{
|
||||
7, 6, 5, 4,
|
||||
0, 1, 2, 3,
|
||||
1, 5, 6, 2,
|
||||
3, 7, 4, 0,
|
||||
2, 6, 7, 3,
|
||||
0, 4, 5, 1,
|
||||
};
|
||||
|
||||
const unsigned char* in = inds;
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
||||
}
|
||||
}
|
||||
|
||||
void duAppendCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
static const int NUM_SEG = 16;
|
||||
static float dir[NUM_SEG*2];
|
||||
static bool init = false;
|
||||
if (!init)
|
||||
{
|
||||
init = true;
|
||||
for (int i = 0; i < NUM_SEG; ++i)
|
||||
{
|
||||
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
|
||||
dir[i*2] = cosf(a);
|
||||
dir[i*2+1] = sinf(a);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int col2 = duMultCol(col, 160);
|
||||
|
||||
const float cx = (maxx + minx)/2;
|
||||
const float cz = (maxz + minz)/2;
|
||||
const float rx = (maxx - minx)/2;
|
||||
const float rz = (maxz - minz)/2;
|
||||
|
||||
for (int i = 2; i < NUM_SEG; ++i)
|
||||
{
|
||||
const int a = 0, b = i-1, c = i;
|
||||
dd->vertex(cx+dir[a*2+0]*rx, miny, cz+dir[a*2+1]*rz, col2);
|
||||
dd->vertex(cx+dir[b*2+0]*rx, miny, cz+dir[b*2+1]*rz, col2);
|
||||
dd->vertex(cx+dir[c*2+0]*rx, miny, cz+dir[c*2+1]*rz, col2);
|
||||
}
|
||||
for (int i = 2; i < NUM_SEG; ++i)
|
||||
{
|
||||
const int a = 0, b = i, c = i-1;
|
||||
dd->vertex(cx+dir[a*2+0]*rx, maxy, cz+dir[a*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[b*2+0]*rx, maxy, cz+dir[b*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[c*2+0]*rx, maxy, cz+dir[c*2+1]*rz, col);
|
||||
}
|
||||
for (int i = 0, j = NUM_SEG-1; i < NUM_SEG; j = i++)
|
||||
{
|
||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col2);
|
||||
dd->vertex(cx+dir[j*2+0]*rx, miny, cz+dir[j*2+1]*rz, col2);
|
||||
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
|
||||
|
||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col2);
|
||||
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz, col);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void evalArc(const float x0, const float y0, const float z0,
|
||||
const float dx, const float dy, const float dz,
|
||||
const float h, const float u, float* res)
|
||||
{
|
||||
res[0] = x0 + dx * u;
|
||||
res[1] = y0 + dy * u + h * (1-(u*2-1)*(u*2-1));
|
||||
res[2] = z0 + dz * u;
|
||||
}
|
||||
|
||||
|
||||
inline void vcross(float* dest, const float* v1, const float* v2)
|
||||
{
|
||||
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||
dest[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||
}
|
||||
|
||||
inline void vnormalize(float* v)
|
||||
{
|
||||
float d = 1.0f / sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
||||
v[0] *= d;
|
||||
v[1] *= d;
|
||||
v[2] *= d;
|
||||
}
|
||||
|
||||
inline void vsub(float* dest, const float* v1, const float* v2)
|
||||
{
|
||||
dest[0] = v1[0]-v2[0];
|
||||
dest[1] = v1[1]-v2[1];
|
||||
dest[2] = v1[2]-v2[2];
|
||||
}
|
||||
|
||||
inline float vdistSqr(const float* v1, const float* v2)
|
||||
{
|
||||
const float x = v1[0]-v2[0];
|
||||
const float y = v1[1]-v2[1];
|
||||
const float z = v1[2]-v2[2];
|
||||
return x*x + y*y + z*z;
|
||||
}
|
||||
|
||||
|
||||
void appendArrowHead(struct duDebugDraw* dd, const float* p, const float* q,
|
||||
const float s, unsigned int col)
|
||||
{
|
||||
const float eps = 0.001f;
|
||||
if (!dd) return;
|
||||
if (vdistSqr(p,q) < eps*eps) return;
|
||||
float ax[3], ay[3] = {0,1,0}, az[3];
|
||||
vsub(az, q, p);
|
||||
vnormalize(az);
|
||||
vcross(ax, ay, az);
|
||||
vcross(ay, az, ax);
|
||||
vnormalize(ay);
|
||||
|
||||
dd->vertex(p, col);
|
||||
// dd->vertex(p[0]+az[0]*s+ay[0]*s/2, p[1]+az[1]*s+ay[1]*s/2, p[2]+az[2]*s+ay[2]*s/2, col);
|
||||
dd->vertex(p[0]+az[0]*s+ax[0]*s/3, p[1]+az[1]*s+ax[1]*s/3, p[2]+az[2]*s+ax[2]*s/3, col);
|
||||
|
||||
dd->vertex(p, col);
|
||||
// dd->vertex(p[0]+az[0]*s-ay[0]*s/2, p[1]+az[1]*s-ay[1]*s/2, p[2]+az[2]*s-ay[2]*s/2, col);
|
||||
dd->vertex(p[0]+az[0]*s-ax[0]*s/3, p[1]+az[1]*s-ax[1]*s/3, p[2]+az[2]*s-ax[2]*s/3, col);
|
||||
|
||||
}
|
||||
|
||||
void duAppendArc(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1, const float h,
|
||||
const float as0, const float as1, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
static const int NUM_ARC_PTS = 8;
|
||||
static const float PAD = 0.05f;
|
||||
static const float ARC_PTS_SCALE = (1.0f-PAD*2) / (float)NUM_ARC_PTS;
|
||||
const float dx = x1 - x0;
|
||||
const float dy = y1 - y0;
|
||||
const float dz = z1 - z0;
|
||||
const float len = sqrtf(dx*dx + dy*dy + dz*dz);
|
||||
float prev[3];
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, PAD, prev);
|
||||
for (int i = 1; i <= NUM_ARC_PTS; ++i)
|
||||
{
|
||||
const float u = PAD + i * ARC_PTS_SCALE;
|
||||
float pt[3];
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, u, pt);
|
||||
dd->vertex(prev[0],prev[1],prev[2], col);
|
||||
dd->vertex(pt[0],pt[1],pt[2], col);
|
||||
prev[0] = pt[0]; prev[1] = pt[1]; prev[2] = pt[2];
|
||||
}
|
||||
|
||||
// End arrows
|
||||
if (as0 > 0.001f)
|
||||
{
|
||||
float p[3], q[3];
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, PAD, p);
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, PAD+0.05f, q);
|
||||
appendArrowHead(dd, p, q, as0, col);
|
||||
}
|
||||
|
||||
if (as1 > 0.001f)
|
||||
{
|
||||
float p[3], q[3];
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, 1-PAD, p);
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, 1-(PAD+0.05f), q);
|
||||
appendArrowHead(dd, p, q, as1, col);
|
||||
}
|
||||
}
|
||||
|
||||
void duAppendArrow(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1,
|
||||
const float as0, const float as1, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->vertex(x0,y0,z0, col);
|
||||
dd->vertex(x1,y1,z1, col);
|
||||
|
||||
// End arrows
|
||||
const float p[3] = {x0,y0,z0}, q[3] = {x1,y1,z1};
|
||||
if (as0 > 0.001f)
|
||||
appendArrowHead(dd, p, q, as0, col);
|
||||
if (as1 > 0.001f)
|
||||
appendArrowHead(dd, q, p, as1, col);
|
||||
}
|
||||
|
||||
void duAppendCircle(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float r, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
static const int NUM_SEG = 40;
|
||||
static float dir[40*2];
|
||||
static bool init = false;
|
||||
if (!init)
|
||||
{
|
||||
init = true;
|
||||
for (int i = 0; i < NUM_SEG; ++i)
|
||||
{
|
||||
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
|
||||
dir[i*2] = cosf(a);
|
||||
dir[i*2+1] = sinf(a);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0, j = NUM_SEG-1; i < NUM_SEG; j = i++)
|
||||
{
|
||||
dd->vertex(x+dir[j*2+0]*r, y, z+dir[j*2+1]*r, col);
|
||||
dd->vertex(x+dir[i*2+0]*r, y, z+dir[i*2+1]*r, col);
|
||||
}
|
||||
}
|
||||
|
||||
void duAppendCross(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float s, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
dd->vertex(x-s,y,z, col);
|
||||
dd->vertex(x+s,y,z, col);
|
||||
dd->vertex(x,y-s,z, col);
|
||||
dd->vertex(x,y+s,z, col);
|
||||
dd->vertex(x,y,z-s, col);
|
||||
dd->vertex(x,y,z+s, col);
|
||||
}
|
||||
|
||||
duDisplayList::duDisplayList(int cap) :
|
||||
m_pos(0),
|
||||
m_color(0),
|
||||
m_size(0),
|
||||
m_cap(0),
|
||||
m_depthMask(true),
|
||||
m_prim(DU_DRAW_LINES),
|
||||
m_primSize(1.0f)
|
||||
{
|
||||
if (cap < 8)
|
||||
cap = 8;
|
||||
resize(cap);
|
||||
}
|
||||
|
||||
duDisplayList::~duDisplayList()
|
||||
{
|
||||
delete [] m_pos;
|
||||
delete [] m_color;
|
||||
}
|
||||
|
||||
void duDisplayList::resize(int cap)
|
||||
{
|
||||
float* newPos = new float[cap*3];
|
||||
if (m_size)
|
||||
memcpy(newPos, m_pos, sizeof(float)*3*m_size);
|
||||
delete [] m_pos;
|
||||
m_pos = newPos;
|
||||
|
||||
unsigned int* newColor = new unsigned int[cap];
|
||||
if (m_size)
|
||||
memcpy(newColor, m_color, sizeof(unsigned int)*m_size);
|
||||
delete [] m_color;
|
||||
m_color = newColor;
|
||||
|
||||
m_cap = cap;
|
||||
}
|
||||
|
||||
void duDisplayList::clear()
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
void duDisplayList::depthMask(bool state)
|
||||
{
|
||||
m_depthMask = state;
|
||||
}
|
||||
|
||||
void duDisplayList::begin(duDebugDrawPrimitives prim, float size)
|
||||
{
|
||||
clear();
|
||||
m_prim = prim;
|
||||
m_primSize = size;
|
||||
}
|
||||
|
||||
void duDisplayList::vertex(const float x, const float y, const float z, unsigned int color)
|
||||
{
|
||||
if (m_size+1 >= m_cap)
|
||||
resize(m_cap*2);
|
||||
float* p = &m_pos[m_size*3];
|
||||
p[0] = x;
|
||||
p[1] = y;
|
||||
p[2] = z;
|
||||
m_color[m_size] = color;
|
||||
m_size++;
|
||||
}
|
||||
|
||||
void duDisplayList::vertex(const float* pos, unsigned int color)
|
||||
{
|
||||
vertex(pos[0],pos[1],pos[2],color);
|
||||
}
|
||||
|
||||
void duDisplayList::end()
|
||||
{
|
||||
}
|
||||
|
||||
void duDisplayList::draw(struct duDebugDraw* dd)
|
||||
{
|
||||
if (!dd) return;
|
||||
if (!m_size) return;
|
||||
dd->depthMask(m_depthMask);
|
||||
dd->begin(m_prim, m_primSize);
|
||||
for (int i = 0; i < m_size; ++i)
|
||||
dd->vertex(&m_pos[i*3], m_color[i]);
|
||||
dd->end();
|
||||
}
|
||||
@@ -0,0 +1,862 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#include "DebugDraw.h"
|
||||
#include "DetourDebugDraw.h"
|
||||
#include "DetourNavMesh.h"
|
||||
#include "DetourCommon.h"
|
||||
#include "DetourNode.h"
|
||||
|
||||
|
||||
static float distancePtLine2d(const float* pt, const float* p, const float* q)
|
||||
{
|
||||
float pqx = q[0] - p[0];
|
||||
float pqz = q[2] - p[2];
|
||||
float dx = pt[0] - p[0];
|
||||
float dz = pt[2] - p[2];
|
||||
float d = pqx*pqx + pqz*pqz;
|
||||
float t = pqx*dx + pqz*dz;
|
||||
if (d != 0) t /= d;
|
||||
dx = p[0] + t*pqx - pt[0];
|
||||
dz = p[2] + t*pqz - pt[2];
|
||||
return dx*dx + dz*dz;
|
||||
}
|
||||
|
||||
static void drawPolyBoundaries(duDebugDraw* dd, const dtMeshTile* tile,
|
||||
const unsigned int col, const float linew,
|
||||
bool inner)
|
||||
{
|
||||
static const float thr = 0.01f*0.01f;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, linew);
|
||||
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[i];
|
||||
|
||||
if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) continue;
|
||||
|
||||
const dtPolyDetail* pd = &tile->detailMeshes[i];
|
||||
|
||||
for (int j = 0, nj = (int)p->vertCount; j < nj; ++j)
|
||||
{
|
||||
unsigned int c = col;
|
||||
if (inner)
|
||||
{
|
||||
if (p->neis[j] == 0) continue;
|
||||
if (p->neis[j] & DT_EXT_LINK)
|
||||
{
|
||||
bool con = false;
|
||||
for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
|
||||
{
|
||||
if (tile->links[k].edge == j)
|
||||
{
|
||||
con = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (con)
|
||||
c = duRGBA(255,255,255,48);
|
||||
else
|
||||
c = duRGBA(0,0,0,48);
|
||||
}
|
||||
else
|
||||
c = duRGBA(0,48,64,32);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p->neis[j] != 0) continue;
|
||||
}
|
||||
|
||||
const float* v0 = &tile->verts[p->verts[j]*3];
|
||||
const float* v1 = &tile->verts[p->verts[(j+1) % nj]*3];
|
||||
|
||||
// Draw detail mesh edges which align with the actual poly edge.
|
||||
// This is really slow.
|
||||
for (int k = 0; k < pd->triCount; ++k)
|
||||
{
|
||||
const unsigned char* t = &tile->detailTris[(pd->triBase+k)*4];
|
||||
const float* tv[3];
|
||||
for (int m = 0; m < 3; ++m)
|
||||
{
|
||||
if (t[m] < p->vertCount)
|
||||
tv[m] = &tile->verts[p->verts[t[m]]*3];
|
||||
else
|
||||
tv[m] = &tile->detailVerts[(pd->vertBase+(t[m]-p->vertCount))*3];
|
||||
}
|
||||
for (int m = 0, n = 2; m < 3; n=m++)
|
||||
{
|
||||
if (((t[3] >> (n*2)) & 0x3) == 0) continue; // Skip inner detail edges.
|
||||
if (distancePtLine2d(tv[n],v0,v1) < thr &&
|
||||
distancePtLine2d(tv[m],v0,v1) < thr)
|
||||
{
|
||||
dd->vertex(tv[n], c);
|
||||
dd->vertex(tv[m], c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
static void drawMeshTile(duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery* query,
|
||||
const dtMeshTile* tile, unsigned char flags)
|
||||
{
|
||||
dtPolyRef base = mesh.getPolyRefBase(tile);
|
||||
|
||||
int tileNum = mesh.decodePolyIdTile(base);
|
||||
const unsigned int tileColor = duIntToCol(tileNum, 128);
|
||||
|
||||
dd->depthMask(false);
|
||||
|
||||
dd->begin(DU_DRAW_TRIS);
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[i];
|
||||
if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) // Skip off-mesh links.
|
||||
continue;
|
||||
|
||||
const dtPolyDetail* pd = &tile->detailMeshes[i];
|
||||
|
||||
unsigned int col;
|
||||
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
||||
col = duRGBA(255,196,0,64);
|
||||
else
|
||||
{
|
||||
if (flags & DU_DRAWNAVMESH_COLOR_TILES)
|
||||
col = tileColor;
|
||||
else
|
||||
col = duTransCol(dd->areaToCol(p->getArea()), 64);
|
||||
}
|
||||
|
||||
for (int j = 0; j < pd->triCount; ++j)
|
||||
{
|
||||
const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4];
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
if (t[k] < p->vertCount)
|
||||
dd->vertex(&tile->verts[p->verts[t[k]]*3], col);
|
||||
else
|
||||
dd->vertex(&tile->detailVerts[(pd->vertBase+t[k]-p->vertCount)*3], col);
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
// Draw inter poly boundaries
|
||||
drawPolyBoundaries(dd, tile, duRGBA(0,48,64,32), 1.5f, true);
|
||||
|
||||
// Draw outer poly boundaries
|
||||
drawPolyBoundaries(dd, tile, duRGBA(0,48,64,220), 2.5f, false);
|
||||
|
||||
if (flags & DU_DRAWNAVMESH_OFFMESHCONS)
|
||||
{
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[i];
|
||||
if (p->getType() != DT_POLYTYPE_OFFMESH_CONNECTION) // Skip regular polys.
|
||||
continue;
|
||||
|
||||
unsigned int col, col2;
|
||||
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
||||
col = duRGBA(255,196,0,220);
|
||||
else
|
||||
col = duDarkenCol(duTransCol(dd->areaToCol(p->getArea()), 220));
|
||||
|
||||
const dtOffMeshConnection* con = &tile->offMeshCons[i - tile->header->offMeshBase];
|
||||
const float* va = &tile->verts[p->verts[0]*3];
|
||||
const float* vb = &tile->verts[p->verts[1]*3];
|
||||
|
||||
// Check to see if start and end end-points have links.
|
||||
bool startSet = false;
|
||||
bool endSet = false;
|
||||
for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
|
||||
{
|
||||
if (tile->links[k].edge == 0)
|
||||
startSet = true;
|
||||
if (tile->links[k].edge == 1)
|
||||
endSet = true;
|
||||
}
|
||||
|
||||
// End points and their on-mesh locations.
|
||||
dd->vertex(va[0],va[1],va[2], col);
|
||||
dd->vertex(con->pos[0],con->pos[1],con->pos[2], col);
|
||||
col2 = startSet ? col : duRGBA(220,32,16,196);
|
||||
duAppendCircle(dd, con->pos[0],con->pos[1]+0.1f,con->pos[2], con->rad, col2);
|
||||
|
||||
dd->vertex(vb[0],vb[1],vb[2], col);
|
||||
dd->vertex(con->pos[3],con->pos[4],con->pos[5], col);
|
||||
col2 = endSet ? col : duRGBA(220,32,16,196);
|
||||
duAppendCircle(dd, con->pos[3],con->pos[4]+0.1f,con->pos[5], con->rad, col2);
|
||||
|
||||
// End point vertices.
|
||||
dd->vertex(con->pos[0],con->pos[1],con->pos[2], duRGBA(0,48,64,196));
|
||||
dd->vertex(con->pos[0],con->pos[1]+0.2f,con->pos[2], duRGBA(0,48,64,196));
|
||||
|
||||
dd->vertex(con->pos[3],con->pos[4],con->pos[5], duRGBA(0,48,64,196));
|
||||
dd->vertex(con->pos[3],con->pos[4]+0.2f,con->pos[5], duRGBA(0,48,64,196));
|
||||
|
||||
// Connection arc.
|
||||
duAppendArc(dd, con->pos[0],con->pos[1],con->pos[2], con->pos[3],con->pos[4],con->pos[5], 0.25f,
|
||||
(con->flags & 1) ? 0.6f : 0, 0.6f, col);
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
const unsigned int vcol = duRGBA(0,0,0,196);
|
||||
dd->begin(DU_DRAW_POINTS, 3.0f);
|
||||
for (int i = 0; i < tile->header->vertCount; ++i)
|
||||
{
|
||||
const float* v = &tile->verts[i*3];
|
||||
dd->vertex(v[0], v[1], v[2], vcol);
|
||||
}
|
||||
dd->end();
|
||||
|
||||
dd->depthMask(true);
|
||||
}
|
||||
|
||||
void duDebugDrawNavMesh(duDebugDraw* dd, const dtNavMesh& mesh, unsigned char flags)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
||||
{
|
||||
const dtMeshTile* tile = mesh.getTile(i);
|
||||
if (!tile->header) continue;
|
||||
drawMeshTile(dd, mesh, 0, tile, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshWithClosedList(struct duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery& query, unsigned char flags)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
const dtNavMeshQuery* q = (flags & DU_DRAWNAVMESH_CLOSEDLIST) ? &query : 0;
|
||||
|
||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
||||
{
|
||||
const dtMeshTile* tile = mesh.getTile(i);
|
||||
if (!tile->header) continue;
|
||||
drawMeshTile(dd, mesh, q, tile, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshNodes(struct duDebugDraw* dd, const dtNavMeshQuery& query)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
const dtNodePool* pool = query.getNodePool();
|
||||
if (pool)
|
||||
{
|
||||
const float off = 0.5f;
|
||||
dd->begin(DU_DRAW_POINTS, 4.0f);
|
||||
for (int i = 0; i < pool->getHashSize(); ++i)
|
||||
{
|
||||
for (dtNodeIndex j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
|
||||
{
|
||||
const dtNode* node = pool->getNodeAtIdx(j+1);
|
||||
if (!node) continue;
|
||||
dd->vertex(node->pos[0],node->pos[1]+off,node->pos[2], duRGBA(255,192,0,255));
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
for (int i = 0; i < pool->getHashSize(); ++i)
|
||||
{
|
||||
for (dtNodeIndex j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
|
||||
{
|
||||
const dtNode* node = pool->getNodeAtIdx(j+1);
|
||||
if (!node) continue;
|
||||
if (!node->pidx) continue;
|
||||
const dtNode* parent = pool->getNodeAtIdx(node->pidx);
|
||||
if (!parent) continue;
|
||||
dd->vertex(node->pos[0],node->pos[1]+off,node->pos[2], duRGBA(255,192,0,128));
|
||||
dd->vertex(parent->pos[0],parent->pos[1]+off,parent->pos[2], duRGBA(255,192,0,128));
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void drawMeshTileBVTree(duDebugDraw* dd, const dtMeshTile* tile)
|
||||
{
|
||||
// Draw BV nodes.
|
||||
const float cs = 1.0f / tile->header->bvQuantFactor;
|
||||
dd->begin(DU_DRAW_LINES, 1.0f);
|
||||
for (int i = 0; i < tile->header->bvNodeCount; ++i)
|
||||
{
|
||||
const dtBVNode* n = &tile->bvTree[i];
|
||||
if (n->i < 0) // Leaf indices are positive.
|
||||
continue;
|
||||
duAppendBoxWire(dd, tile->header->bmin[0] + n->bmin[0]*cs,
|
||||
tile->header->bmin[1] + n->bmin[1]*cs,
|
||||
tile->header->bmin[2] + n->bmin[2]*cs,
|
||||
tile->header->bmin[0] + n->bmax[0]*cs,
|
||||
tile->header->bmin[1] + n->bmax[1]*cs,
|
||||
tile->header->bmin[2] + n->bmax[2]*cs,
|
||||
duRGBA(255,255,255,128));
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshBVTree(duDebugDraw* dd, const dtNavMesh& mesh)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
||||
{
|
||||
const dtMeshTile* tile = mesh.getTile(i);
|
||||
if (!tile->header) continue;
|
||||
drawMeshTileBVTree(dd, tile);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawMeshTilePortal(duDebugDraw* dd, const dtMeshTile* tile)
|
||||
{
|
||||
// Draw portals
|
||||
const float padx = 0.04f;
|
||||
const float pady = tile->header->walkableClimb;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
|
||||
for (int side = 0; side < 8; ++side)
|
||||
{
|
||||
unsigned short m = DT_EXT_LINK | (unsigned short)side;
|
||||
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
dtPoly* poly = &tile->polys[i];
|
||||
|
||||
// Create new links.
|
||||
const int nv = poly->vertCount;
|
||||
for (int j = 0; j < nv; ++j)
|
||||
{
|
||||
// Skip edges which do not point to the right side.
|
||||
if (poly->neis[j] != m)
|
||||
continue;
|
||||
|
||||
// Create new links
|
||||
const float* va = &tile->verts[poly->verts[j]*3];
|
||||
const float* vb = &tile->verts[poly->verts[(j+1) % nv]*3];
|
||||
|
||||
if (side == 0 || side == 4)
|
||||
{
|
||||
unsigned int col = side == 0 ? duRGBA(128,0,0,128) : duRGBA(128,0,128,128);
|
||||
|
||||
const float x = va[0] + ((side == 0) ? -padx : padx);
|
||||
|
||||
dd->vertex(x,va[1]-pady,va[2], col);
|
||||
dd->vertex(x,va[1]+pady,va[2], col);
|
||||
|
||||
dd->vertex(x,va[1]+pady,va[2], col);
|
||||
dd->vertex(x,vb[1]+pady,vb[2], col);
|
||||
|
||||
dd->vertex(x,vb[1]+pady,vb[2], col);
|
||||
dd->vertex(x,vb[1]-pady,vb[2], col);
|
||||
|
||||
dd->vertex(x,vb[1]-pady,vb[2], col);
|
||||
dd->vertex(x,va[1]-pady,va[2], col);
|
||||
}
|
||||
else if (side == 2 || side == 6)
|
||||
{
|
||||
unsigned int col = side == 2 ? duRGBA(0,128,0,128) : duRGBA(0,128,128,128);
|
||||
|
||||
const float z = va[2] + ((side == 2) ? -padx : padx);
|
||||
|
||||
dd->vertex(va[0],va[1]-pady,z, col);
|
||||
dd->vertex(va[0],va[1]+pady,z, col);
|
||||
|
||||
dd->vertex(va[0],va[1]+pady,z, col);
|
||||
dd->vertex(vb[0],vb[1]+pady,z, col);
|
||||
|
||||
dd->vertex(vb[0],vb[1]+pady,z, col);
|
||||
dd->vertex(vb[0],vb[1]-pady,z, col);
|
||||
|
||||
dd->vertex(vb[0],vb[1]-pady,z, col);
|
||||
dd->vertex(va[0],va[1]-pady,z, col);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshPortals(duDebugDraw* dd, const dtNavMesh& mesh)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
||||
{
|
||||
const dtMeshTile* tile = mesh.getTile(i);
|
||||
if (!tile->header) continue;
|
||||
drawMeshTilePortal(dd, tile);
|
||||
}
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshPolysWithFlags(struct duDebugDraw* dd, const dtNavMesh& mesh,
|
||||
const unsigned short polyFlags, const unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
||||
{
|
||||
const dtMeshTile* tile = mesh.getTile(i);
|
||||
if (!tile->header) continue;
|
||||
dtPolyRef base = mesh.getPolyRefBase(tile);
|
||||
|
||||
for (int j = 0; j < tile->header->polyCount; ++j)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[j];
|
||||
if ((p->flags & polyFlags) == 0) continue;
|
||||
duDebugDrawNavMeshPoly(dd, mesh, base|(dtPolyRef)j, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshPoly(duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
const dtMeshTile* tile = 0;
|
||||
const dtPoly* poly = 0;
|
||||
if (dtStatusFailed(mesh.getTileAndPolyByRef(ref, &tile, &poly)))
|
||||
return;
|
||||
|
||||
dd->depthMask(false);
|
||||
|
||||
const unsigned int c = duTransCol(col, 64);
|
||||
const unsigned int ip = (unsigned int)(poly - tile->polys);
|
||||
|
||||
if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||
{
|
||||
dtOffMeshConnection* con = &tile->offMeshCons[ip - tile->header->offMeshBase];
|
||||
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
|
||||
// Connection arc.
|
||||
duAppendArc(dd, con->pos[0],con->pos[1],con->pos[2], con->pos[3],con->pos[4],con->pos[5], 0.25f,
|
||||
(con->flags & 1) ? 0.6f : 0.0f, 0.6f, c);
|
||||
|
||||
dd->end();
|
||||
}
|
||||
else
|
||||
{
|
||||
const dtPolyDetail* pd = &tile->detailMeshes[ip];
|
||||
|
||||
dd->begin(DU_DRAW_TRIS);
|
||||
for (int i = 0; i < pd->triCount; ++i)
|
||||
{
|
||||
const unsigned char* t = &tile->detailTris[(pd->triBase+i)*4];
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
if (t[j] < poly->vertCount)
|
||||
dd->vertex(&tile->verts[poly->verts[t[j]]*3], c);
|
||||
else
|
||||
dd->vertex(&tile->detailVerts[(pd->vertBase+t[j]-poly->vertCount)*3], c);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
dd->depthMask(true);
|
||||
|
||||
}
|
||||
|
||||
static void debugDrawTileCachePortals(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
||||
{
|
||||
const int w = (int)layer.header->width;
|
||||
const int h = (int)layer.header->height;
|
||||
const float* bmin = layer.header->bmin;
|
||||
|
||||
// Portals
|
||||
unsigned int pcol = duRGBA(255,255,255,255);
|
||||
|
||||
const int segs[4*4] = {0,0,0,1, 0,1,1,1, 1,1,1,0, 1,0,0,0};
|
||||
|
||||
// Layer portals
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const int idx = x+y*w;
|
||||
const int lh = (int)layer.heights[idx];
|
||||
if (lh == 0xff) continue;
|
||||
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
{
|
||||
if (layer.cons[idx] & (1<<(dir+4)))
|
||||
{
|
||||
const int* seg = &segs[dir*4];
|
||||
const float ax = bmin[0] + (x+seg[0])*cs;
|
||||
const float ay = bmin[1] + (lh+2)*ch;
|
||||
const float az = bmin[2] + (y+seg[1])*cs;
|
||||
const float bx = bmin[0] + (x+seg[2])*cs;
|
||||
const float by = bmin[1] + (lh+2)*ch;
|
||||
const float bz = bmin[2] + (y+seg[3])*cs;
|
||||
dd->vertex(ax, ay, az, pcol);
|
||||
dd->vertex(bx, by, bz, pcol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawTileCacheLayerAreas(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
||||
{
|
||||
const int w = (int)layer.header->width;
|
||||
const int h = (int)layer.header->height;
|
||||
const float* bmin = layer.header->bmin;
|
||||
const float* bmax = layer.header->bmax;
|
||||
const int idx = layer.header->tlayer;
|
||||
|
||||
unsigned int color = duIntToCol(idx+1, 255);
|
||||
|
||||
// Layer bounds
|
||||
float lbmin[3], lbmax[3];
|
||||
lbmin[0] = bmin[0] + layer.header->minx*cs;
|
||||
lbmin[1] = bmin[1];
|
||||
lbmin[2] = bmin[2] + layer.header->miny*cs;
|
||||
lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs;
|
||||
lbmax[1] = bmax[1];
|
||||
lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs;
|
||||
duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f);
|
||||
|
||||
// Layer height
|
||||
dd->begin(DU_DRAW_QUADS);
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const int lidx = x+y*w;
|
||||
const int lh = (int)layer.heights[lidx];
|
||||
if (lh == 0xff) continue;
|
||||
|
||||
const unsigned char area = layer.areas[lidx];
|
||||
unsigned int col;
|
||||
if (area == 63)
|
||||
col = duLerpCol(color, duRGBA(0,192,255,64), 32);
|
||||
else if (area == 0)
|
||||
col = duLerpCol(color, duRGBA(0,0,0,64), 32);
|
||||
else
|
||||
col = duLerpCol(color, dd->areaToCol(area), 32);
|
||||
|
||||
const float fx = bmin[0] + x*cs;
|
||||
const float fy = bmin[1] + (lh+1)*ch;
|
||||
const float fz = bmin[2] + y*cs;
|
||||
|
||||
dd->vertex(fx, fy, fz, col);
|
||||
dd->vertex(fx, fy, fz+cs, col);
|
||||
dd->vertex(fx+cs, fy, fz+cs, col);
|
||||
dd->vertex(fx+cs, fy, fz, col);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
debugDrawTileCachePortals(dd, layer, cs, ch);
|
||||
}
|
||||
|
||||
void duDebugDrawTileCacheLayerRegions(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
||||
{
|
||||
const int w = (int)layer.header->width;
|
||||
const int h = (int)layer.header->height;
|
||||
const float* bmin = layer.header->bmin;
|
||||
const float* bmax = layer.header->bmax;
|
||||
const int idx = layer.header->tlayer;
|
||||
|
||||
unsigned int color = duIntToCol(idx+1, 255);
|
||||
|
||||
// Layer bounds
|
||||
float lbmin[3], lbmax[3];
|
||||
lbmin[0] = bmin[0] + layer.header->minx*cs;
|
||||
lbmin[1] = bmin[1];
|
||||
lbmin[2] = bmin[2] + layer.header->miny*cs;
|
||||
lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs;
|
||||
lbmax[1] = bmax[1];
|
||||
lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs;
|
||||
duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f);
|
||||
|
||||
// Layer height
|
||||
dd->begin(DU_DRAW_QUADS);
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const int lidx = x+y*w;
|
||||
const int lh = (int)layer.heights[lidx];
|
||||
if (lh == 0xff) continue;
|
||||
const unsigned char reg = layer.regs[lidx];
|
||||
|
||||
unsigned int col = duLerpCol(color, duIntToCol(reg, 255), 192);
|
||||
|
||||
const float fx = bmin[0] + x*cs;
|
||||
const float fy = bmin[1] + (lh+1)*ch;
|
||||
const float fz = bmin[2] + y*cs;
|
||||
|
||||
dd->vertex(fx, fy, fz, col);
|
||||
dd->vertex(fx, fy, fz+cs, col);
|
||||
dd->vertex(fx+cs, fy, fz+cs, col);
|
||||
dd->vertex(fx+cs, fy, fz, col);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
debugDrawTileCachePortals(dd, layer, cs, ch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*struct dtTileCacheContour
|
||||
{
|
||||
int nverts;
|
||||
unsigned char* verts;
|
||||
unsigned char reg;
|
||||
unsigned char area;
|
||||
};
|
||||
|
||||
struct dtTileCacheContourSet
|
||||
{
|
||||
int nconts;
|
||||
dtTileCacheContour* conts;
|
||||
};*/
|
||||
|
||||
void duDebugDrawTileCacheContours(duDebugDraw* dd, const struct dtTileCacheContourSet& lcset,
|
||||
const float* orig, const float cs, const float ch)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
const unsigned char a = 255;// (unsigned char)(alpha*255.0f);
|
||||
|
||||
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
|
||||
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
|
||||
for (int i = 0; i < lcset.nconts; ++i)
|
||||
{
|
||||
const dtTileCacheContour& c = lcset.conts[i];
|
||||
unsigned int color = 0;
|
||||
|
||||
color = duIntToCol(i, a);
|
||||
|
||||
for (int j = 0; j < c.nverts; ++j)
|
||||
{
|
||||
const int k = (j+1) % c.nverts;
|
||||
const unsigned char* va = &c.verts[j*4];
|
||||
const unsigned char* vb = &c.verts[k*4];
|
||||
const float ax = orig[0] + va[0]*cs;
|
||||
const float ay = orig[1] + (va[1]+1+(i&1))*ch;
|
||||
const float az = orig[2] + va[2]*cs;
|
||||
const float bx = orig[0] + vb[0]*cs;
|
||||
const float by = orig[1] + (vb[1]+1+(i&1))*ch;
|
||||
const float bz = orig[2] + vb[2]*cs;
|
||||
unsigned int col = color;
|
||||
if ((va[3] & 0xf) != 0xf)
|
||||
{
|
||||
// Portal segment
|
||||
col = duRGBA(255,255,255,128);
|
||||
int d = va[3] & 0xf;
|
||||
|
||||
const float cx = (ax+bx)*0.5f;
|
||||
const float cy = (ay+by)*0.5f;
|
||||
const float cz = (az+bz)*0.5f;
|
||||
|
||||
const float dx = cx + offs[d*2+0]*2*cs;
|
||||
const float dy = cy;
|
||||
const float dz = cz + offs[d*2+1]*2*cs;
|
||||
|
||||
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
|
||||
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
|
||||
}
|
||||
|
||||
duAppendArrow(dd, ax,ay,az, bx,by,bz, 0.0f, cs*0.5f, col);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
dd->begin(DU_DRAW_POINTS, 4.0f);
|
||||
|
||||
for (int i = 0; i < lcset.nconts; ++i)
|
||||
{
|
||||
const dtTileCacheContour& c = lcset.conts[i];
|
||||
unsigned int color = 0;
|
||||
|
||||
for (int j = 0; j < c.nverts; ++j)
|
||||
{
|
||||
const unsigned char* va = &c.verts[j*4];
|
||||
|
||||
color = duDarkenCol(duIntToCol(i, a));
|
||||
if (va[3] & 0x80)
|
||||
{
|
||||
// Border vertex
|
||||
color = duRGBA(255,0,0,255);
|
||||
}
|
||||
|
||||
float fx = orig[0] + va[0]*cs;
|
||||
float fy = orig[1] + (va[1]+1+(i&1))*ch;
|
||||
float fz = orig[2] + va[2]*cs;
|
||||
dd->vertex(fx,fy,fz, color);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawTileCachePolyMesh(duDebugDraw* dd, const struct dtTileCachePolyMesh& lmesh,
|
||||
const float* orig, const float cs, const float ch)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
const int nvp = lmesh.nvp;
|
||||
|
||||
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
|
||||
|
||||
dd->begin(DU_DRAW_TRIS);
|
||||
|
||||
for (int i = 0; i < lmesh.npolys; ++i)
|
||||
{
|
||||
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||
const unsigned char area = lmesh.areas[i];
|
||||
|
||||
unsigned int color;
|
||||
if (area == DT_TILECACHE_WALKABLE_AREA)
|
||||
color = duRGBA(0,192,255,64);
|
||||
else if (area == DT_TILECACHE_NULL_AREA)
|
||||
color = duRGBA(0,0,0,64);
|
||||
else
|
||||
color = dd->areaToCol(area);
|
||||
|
||||
unsigned short vi[3];
|
||||
for (int j = 2; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
||||
vi[0] = p[0];
|
||||
vi[1] = p[j-1];
|
||||
vi[2] = p[j];
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+1)*ch;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
dd->vertex(x,y,z, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
// Draw neighbours edges
|
||||
const unsigned int coln = duRGBA(0,48,64,32);
|
||||
dd->begin(DU_DRAW_LINES, 1.5f);
|
||||
for (int i = 0; i < lmesh.npolys; ++i)
|
||||
{
|
||||
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
||||
if (p[nvp+j] & 0x8000) continue;
|
||||
const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1;
|
||||
int vi[2] = {p[j], p[nj]};
|
||||
|
||||
for (int k = 0; k < 2; ++k)
|
||||
{
|
||||
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
dd->vertex(x, y, z, coln);
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
// Draw boundary edges
|
||||
const unsigned int colb = duRGBA(0,48,64,220);
|
||||
dd->begin(DU_DRAW_LINES, 2.5f);
|
||||
for (int i = 0; i < lmesh.npolys; ++i)
|
||||
{
|
||||
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
||||
if ((p[nvp+j] & 0x8000) == 0) continue;
|
||||
const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1;
|
||||
int vi[2] = {p[j], p[nj]};
|
||||
|
||||
unsigned int col = colb;
|
||||
if ((p[nvp+j] & 0xf) != 0xf)
|
||||
{
|
||||
const unsigned short* va = &lmesh.verts[vi[0]*3];
|
||||
const unsigned short* vb = &lmesh.verts[vi[1]*3];
|
||||
|
||||
const float ax = orig[0] + va[0]*cs;
|
||||
const float ay = orig[1] + (va[1]+1+(i&1))*ch;
|
||||
const float az = orig[2] + va[2]*cs;
|
||||
const float bx = orig[0] + vb[0]*cs;
|
||||
const float by = orig[1] + (vb[1]+1+(i&1))*ch;
|
||||
const float bz = orig[2] + vb[2]*cs;
|
||||
|
||||
const float cx = (ax+bx)*0.5f;
|
||||
const float cy = (ay+by)*0.5f;
|
||||
const float cz = (az+bz)*0.5f;
|
||||
|
||||
int d = p[nvp+j] & 0xf;
|
||||
|
||||
const float dx = cx + offs[d*2+0]*2*cs;
|
||||
const float dy = cy;
|
||||
const float dz = cz + offs[d*2+1]*2*cs;
|
||||
|
||||
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
|
||||
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
|
||||
|
||||
col = duRGBA(255,255,255,128);
|
||||
}
|
||||
|
||||
for (int k = 0; k < 2; ++k)
|
||||
{
|
||||
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
dd->vertex(x, y, z, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
dd->begin(DU_DRAW_POINTS, 3.0f);
|
||||
const unsigned int colv = duRGBA(0,0,0,220);
|
||||
for (int i = 0; i < lmesh.nverts; ++i)
|
||||
{
|
||||
const unsigned short* v = &lmesh.verts[i*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
dd->vertex(x,y,z, colv);
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,451 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "Recast.h"
|
||||
#include "RecastAlloc.h"
|
||||
#include "RecastDump.h"
|
||||
|
||||
|
||||
duFileIO::~duFileIO()
|
||||
{
|
||||
// Empty
|
||||
}
|
||||
|
||||
static void ioprintf(duFileIO* io, const char* format, ...)
|
||||
{
|
||||
char line[256];
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
const int n = vsnprintf(line, sizeof(line), format, ap);
|
||||
va_end(ap);
|
||||
if (n > 0)
|
||||
io->write(line, sizeof(char)*n);
|
||||
}
|
||||
|
||||
bool duDumpPolyMeshToObj(rcPolyMesh& pmesh, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duDumpPolyMeshToObj: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isWriting())
|
||||
{
|
||||
printf("duDumpPolyMeshToObj: input IO not writing.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const int nvp = pmesh.nvp;
|
||||
const float cs = pmesh.cs;
|
||||
const float ch = pmesh.ch;
|
||||
const float* orig = pmesh.bmin;
|
||||
|
||||
ioprintf(io, "# Recast Navmesh\n");
|
||||
ioprintf(io, "o NavMesh\n");
|
||||
|
||||
ioprintf(io, "\n");
|
||||
|
||||
for (int i = 0; i < pmesh.nverts; ++i)
|
||||
{
|
||||
const unsigned short* v = &pmesh.verts[i*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
ioprintf(io, "v %f %f %f\n", x,y,z);
|
||||
}
|
||||
|
||||
ioprintf(io, "\n");
|
||||
|
||||
for (int i = 0; i < pmesh.npolys; ++i)
|
||||
{
|
||||
const unsigned short* p = &pmesh.polys[i*nvp*2];
|
||||
for (int j = 2; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == RC_MESH_NULL_IDX) break;
|
||||
ioprintf(io, "f %d %d %d\n", p[0]+1, p[j-1]+1, p[j]+1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool duDumpPolyMeshDetailToObj(rcPolyMeshDetail& dmesh, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duDumpPolyMeshDetailToObj: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isWriting())
|
||||
{
|
||||
printf("duDumpPolyMeshDetailToObj: input IO not writing.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ioprintf(io, "# Recast Navmesh\n");
|
||||
ioprintf(io, "o NavMesh\n");
|
||||
|
||||
ioprintf(io, "\n");
|
||||
|
||||
for (int i = 0; i < dmesh.nverts; ++i)
|
||||
{
|
||||
const float* v = &dmesh.verts[i*3];
|
||||
ioprintf(io, "v %f %f %f\n", v[0],v[1],v[2]);
|
||||
}
|
||||
|
||||
ioprintf(io, "\n");
|
||||
|
||||
for (int i = 0; i < dmesh.nmeshes; ++i)
|
||||
{
|
||||
const unsigned int* m = &dmesh.meshes[i*4];
|
||||
const unsigned int bverts = m[0];
|
||||
const unsigned int btris = m[2];
|
||||
const unsigned int ntris = m[3];
|
||||
const unsigned char* tris = &dmesh.tris[btris*4];
|
||||
for (unsigned int j = 0; j < ntris; ++j)
|
||||
{
|
||||
ioprintf(io, "f %d %d %d\n",
|
||||
(int)(bverts+tris[j*4+0])+1,
|
||||
(int)(bverts+tris[j*4+1])+1,
|
||||
(int)(bverts+tris[j*4+2])+1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const int CSET_MAGIC = ('c' << 24) | ('s' << 16) | ('e' << 8) | 't';
|
||||
static const int CSET_VERSION = 2;
|
||||
|
||||
bool duDumpContourSet(struct rcContourSet& cset, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duDumpContourSet: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isWriting())
|
||||
{
|
||||
printf("duDumpContourSet: input IO not writing.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
io->write(&CSET_MAGIC, sizeof(CSET_MAGIC));
|
||||
io->write(&CSET_VERSION, sizeof(CSET_VERSION));
|
||||
|
||||
io->write(&cset.nconts, sizeof(cset.nconts));
|
||||
|
||||
io->write(cset.bmin, sizeof(cset.bmin));
|
||||
io->write(cset.bmax, sizeof(cset.bmax));
|
||||
|
||||
io->write(&cset.cs, sizeof(cset.cs));
|
||||
io->write(&cset.ch, sizeof(cset.ch));
|
||||
|
||||
io->write(&cset.width, sizeof(cset.width));
|
||||
io->write(&cset.height, sizeof(cset.height));
|
||||
io->write(&cset.borderSize, sizeof(cset.borderSize));
|
||||
|
||||
for (int i = 0; i < cset.nconts; ++i)
|
||||
{
|
||||
const rcContour& cont = cset.conts[i];
|
||||
io->write(&cont.nverts, sizeof(cont.nverts));
|
||||
io->write(&cont.nrverts, sizeof(cont.nrverts));
|
||||
io->write(&cont.reg, sizeof(cont.reg));
|
||||
io->write(&cont.area, sizeof(cont.area));
|
||||
io->write(cont.verts, sizeof(int)*4*cont.nverts);
|
||||
io->write(cont.rverts, sizeof(int)*4*cont.nrverts);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool duReadContourSet(struct rcContourSet& cset, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duReadContourSet: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isReading())
|
||||
{
|
||||
printf("duReadContourSet: input IO not reading.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int magic = 0;
|
||||
int version = 0;
|
||||
|
||||
io->read(&magic, sizeof(magic));
|
||||
io->read(&version, sizeof(version));
|
||||
|
||||
if (magic != CSET_MAGIC)
|
||||
{
|
||||
printf("duReadContourSet: Bad voodoo.\n");
|
||||
return false;
|
||||
}
|
||||
if (version != CSET_VERSION)
|
||||
{
|
||||
printf("duReadContourSet: Bad version.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
io->read(&cset.nconts, sizeof(cset.nconts));
|
||||
|
||||
cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*cset.nconts, RC_ALLOC_PERM);
|
||||
if (!cset.conts)
|
||||
{
|
||||
printf("duReadContourSet: Could not alloc contours (%d)\n", cset.nconts);
|
||||
return false;
|
||||
}
|
||||
memset(cset.conts, 0, sizeof(rcContour)*cset.nconts);
|
||||
|
||||
io->read(cset.bmin, sizeof(cset.bmin));
|
||||
io->read(cset.bmax, sizeof(cset.bmax));
|
||||
|
||||
io->read(&cset.cs, sizeof(cset.cs));
|
||||
io->read(&cset.ch, sizeof(cset.ch));
|
||||
|
||||
io->read(&cset.width, sizeof(cset.width));
|
||||
io->read(&cset.height, sizeof(cset.height));
|
||||
io->read(&cset.borderSize, sizeof(cset.borderSize));
|
||||
|
||||
for (int i = 0; i < cset.nconts; ++i)
|
||||
{
|
||||
rcContour& cont = cset.conts[i];
|
||||
io->read(&cont.nverts, sizeof(cont.nverts));
|
||||
io->read(&cont.nrverts, sizeof(cont.nrverts));
|
||||
io->read(&cont.reg, sizeof(cont.reg));
|
||||
io->read(&cont.area, sizeof(cont.area));
|
||||
|
||||
cont.verts = (int*)rcAlloc(sizeof(int)*4*cont.nverts, RC_ALLOC_PERM);
|
||||
if (!cont.verts)
|
||||
{
|
||||
printf("duReadContourSet: Could not alloc contour verts (%d)\n", cont.nverts);
|
||||
return false;
|
||||
}
|
||||
cont.rverts = (int*)rcAlloc(sizeof(int)*4*cont.nrverts, RC_ALLOC_PERM);
|
||||
if (!cont.rverts)
|
||||
{
|
||||
printf("duReadContourSet: Could not alloc contour rverts (%d)\n", cont.nrverts);
|
||||
return false;
|
||||
}
|
||||
|
||||
io->read(cont.verts, sizeof(int)*4*cont.nverts);
|
||||
io->read(cont.rverts, sizeof(int)*4*cont.nrverts);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static const int CHF_MAGIC = ('r' << 24) | ('c' << 16) | ('h' << 8) | 'f';
|
||||
static const int CHF_VERSION = 3;
|
||||
|
||||
bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duDumpCompactHeightfield: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isWriting())
|
||||
{
|
||||
printf("duDumpCompactHeightfield: input IO not writing.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
io->write(&CHF_MAGIC, sizeof(CHF_MAGIC));
|
||||
io->write(&CHF_VERSION, sizeof(CHF_VERSION));
|
||||
|
||||
io->write(&chf.width, sizeof(chf.width));
|
||||
io->write(&chf.height, sizeof(chf.height));
|
||||
io->write(&chf.spanCount, sizeof(chf.spanCount));
|
||||
|
||||
io->write(&chf.walkableHeight, sizeof(chf.walkableHeight));
|
||||
io->write(&chf.walkableClimb, sizeof(chf.walkableClimb));
|
||||
io->write(&chf.borderSize, sizeof(chf.borderSize));
|
||||
|
||||
io->write(&chf.maxDistance, sizeof(chf.maxDistance));
|
||||
io->write(&chf.maxRegions, sizeof(chf.maxRegions));
|
||||
|
||||
io->write(chf.bmin, sizeof(chf.bmin));
|
||||
io->write(chf.bmax, sizeof(chf.bmax));
|
||||
|
||||
io->write(&chf.cs, sizeof(chf.cs));
|
||||
io->write(&chf.ch, sizeof(chf.ch));
|
||||
|
||||
int tmp = 0;
|
||||
if (chf.cells) tmp |= 1;
|
||||
if (chf.spans) tmp |= 2;
|
||||
if (chf.dist) tmp |= 4;
|
||||
if (chf.areas) tmp |= 8;
|
||||
|
||||
io->write(&tmp, sizeof(tmp));
|
||||
|
||||
if (chf.cells)
|
||||
io->write(chf.cells, sizeof(rcCompactCell)*chf.width*chf.height);
|
||||
if (chf.spans)
|
||||
io->write(chf.spans, sizeof(rcCompactSpan)*chf.spanCount);
|
||||
if (chf.dist)
|
||||
io->write(chf.dist, sizeof(unsigned short)*chf.spanCount);
|
||||
if (chf.areas)
|
||||
io->write(chf.areas, sizeof(unsigned char)*chf.spanCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool duReadCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duReadCompactHeightfield: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isReading())
|
||||
{
|
||||
printf("duReadCompactHeightfield: input IO not reading.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int magic = 0;
|
||||
int version = 0;
|
||||
|
||||
io->read(&magic, sizeof(magic));
|
||||
io->read(&version, sizeof(version));
|
||||
|
||||
if (magic != CHF_MAGIC)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Bad voodoo.\n");
|
||||
return false;
|
||||
}
|
||||
if (version != CHF_VERSION)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Bad version.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
io->read(&chf.width, sizeof(chf.width));
|
||||
io->read(&chf.height, sizeof(chf.height));
|
||||
io->read(&chf.spanCount, sizeof(chf.spanCount));
|
||||
|
||||
io->read(&chf.walkableHeight, sizeof(chf.walkableHeight));
|
||||
io->read(&chf.walkableClimb, sizeof(chf.walkableClimb));
|
||||
io->read(&chf.borderSize, sizeof(chf.borderSize));
|
||||
|
||||
io->read(&chf.maxDistance, sizeof(chf.maxDistance));
|
||||
io->read(&chf.maxRegions, sizeof(chf.maxRegions));
|
||||
|
||||
io->read(chf.bmin, sizeof(chf.bmin));
|
||||
io->read(chf.bmax, sizeof(chf.bmax));
|
||||
|
||||
io->read(&chf.cs, sizeof(chf.cs));
|
||||
io->read(&chf.ch, sizeof(chf.ch));
|
||||
|
||||
int tmp = 0;
|
||||
io->read(&tmp, sizeof(tmp));
|
||||
|
||||
if (tmp & 1)
|
||||
{
|
||||
chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*chf.width*chf.height, RC_ALLOC_PERM);
|
||||
if (!chf.cells)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Could not alloc cells (%d)\n", chf.width*chf.height);
|
||||
return false;
|
||||
}
|
||||
io->read(chf.cells, sizeof(rcCompactCell)*chf.width*chf.height);
|
||||
}
|
||||
if (tmp & 2)
|
||||
{
|
||||
chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*chf.spanCount, RC_ALLOC_PERM);
|
||||
if (!chf.spans)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Could not alloc spans (%d)\n", chf.spanCount);
|
||||
return false;
|
||||
}
|
||||
io->read(chf.spans, sizeof(rcCompactSpan)*chf.spanCount);
|
||||
}
|
||||
if (tmp & 4)
|
||||
{
|
||||
chf.dist = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_PERM);
|
||||
if (!chf.dist)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Could not alloc dist (%d)\n", chf.spanCount);
|
||||
return false;
|
||||
}
|
||||
io->read(chf.dist, sizeof(unsigned short)*chf.spanCount);
|
||||
}
|
||||
if (tmp & 8)
|
||||
{
|
||||
chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_PERM);
|
||||
if (!chf.areas)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Could not alloc areas (%d)\n", chf.spanCount);
|
||||
return false;
|
||||
}
|
||||
io->read(chf.areas, sizeof(unsigned char)*chf.spanCount);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void logLine(rcContext& ctx, rcTimerLabel label, const char* name, const float pc)
|
||||
{
|
||||
const int t = ctx.getAccumulatedTime(label);
|
||||
if (t < 0) return;
|
||||
ctx.log(RC_LOG_PROGRESS, "%s:\t%.2fms\t(%.1f%%)", name, t/1000.0f, t*pc);
|
||||
}
|
||||
|
||||
void duLogBuildTimes(rcContext& ctx, const int totalTimeUsec)
|
||||
{
|
||||
const float pc = 100.0f / totalTimeUsec;
|
||||
|
||||
ctx.log(RC_LOG_PROGRESS, "Build Times");
|
||||
logLine(ctx, RC_TIMER_RASTERIZE_TRIANGLES, "- Rasterize", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_COMPACTHEIGHTFIELD, "- Build Compact", pc);
|
||||
logLine(ctx, RC_TIMER_FILTER_BORDER, "- Filter Border", pc);
|
||||
logLine(ctx, RC_TIMER_FILTER_WALKABLE, "- Filter Walkable", pc);
|
||||
logLine(ctx, RC_TIMER_ERODE_AREA, "- Erode Area", pc);
|
||||
logLine(ctx, RC_TIMER_MEDIAN_AREA, "- Median Area", pc);
|
||||
logLine(ctx, RC_TIMER_MARK_BOX_AREA, "- Mark Box Area", pc);
|
||||
logLine(ctx, RC_TIMER_MARK_CONVEXPOLY_AREA, "- Mark Convex Area", pc);
|
||||
logLine(ctx, RC_TIMER_MARK_CYLINDER_AREA, "- Mark Cylinder Area", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD, "- Build Distance Field", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_DIST, " - Distance", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_BLUR, " - Blur", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_REGIONS, "- Build Regions", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_WATERSHED, " - Watershed", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_EXPAND, " - Expand", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_FLOOD, " - Find Basins", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_FILTER, " - Filter", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_LAYERS, "- Build Layers", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS, "- Build Contours", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS_TRACE, " - Trace", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS_SIMPLIFY, " - Simplify", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_POLYMESH, "- Build Polymesh", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_POLYMESHDETAIL, "- Build Polymesh Detail", pc);
|
||||
logLine(ctx, RC_TIMER_MERGE_POLYMESH, "- Merge Polymeshes", pc);
|
||||
logLine(ctx, RC_TIMER_MERGE_POLYMESHDETAIL, "- Merge Polymesh Details", pc);
|
||||
ctx.log(RC_LOG_PROGRESS, "=== TOTAL:\t%.2fms", totalTimeUsec/1000.0f);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef DETOURALLOCATOR_H
|
||||
#define DETOURALLOCATOR_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/// Provides hint values to the memory allocator on how long the
|
||||
/// memory is expected to be used.
|
||||
enum dtAllocHint
|
||||
{
|
||||
DT_ALLOC_PERM, ///< Memory persist after a function call.
|
||||
DT_ALLOC_TEMP ///< Memory used temporarily within a function.
|
||||
};
|
||||
|
||||
/// A memory allocation function.
|
||||
// @param[in] size The size, in bytes of memory, to allocate.
|
||||
// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.
|
||||
// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||
/// @see dtAllocSetCustom
|
||||
typedef void* (dtAllocFunc)(size_t size, dtAllocHint hint);
|
||||
|
||||
/// A memory deallocation function.
|
||||
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAllocFunc.
|
||||
/// @see dtAllocSetCustom
|
||||
typedef void (dtFreeFunc)(void* ptr);
|
||||
|
||||
/// Sets the base custom allocation functions to be used by Detour.
|
||||
/// @param[in] allocFunc The memory allocation function to be used by #dtAlloc
|
||||
/// @param[in] freeFunc The memory de-allocation function to be used by #dtFree
|
||||
void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc);
|
||||
|
||||
/// Allocates a memory block.
|
||||
/// @param[in] size The size, in bytes of memory, to allocate.
|
||||
/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
|
||||
/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||
/// @see dtFree
|
||||
void* dtAlloc(size_t size, dtAllocHint hint);
|
||||
|
||||
/// Deallocates a memory block.
|
||||
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAlloc.
|
||||
/// @see dtAlloc
|
||||
void dtFree(void* ptr);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef DETOURASSERT_H
|
||||
#define DETOURASSERT_H
|
||||
|
||||
// Note: This header file's only purpose is to include define assert.
|
||||
// Feel free to change the file and include your own implementation instead.
|
||||
|
||||
#ifdef NDEBUG
|
||||
|
||||
// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
|
||||
# define dtAssert(x) do { (void)sizeof(x); } while((void)(__LINE__==-1),false)
|
||||
|
||||
#else
|
||||
|
||||
/// An assertion failure function.
|
||||
// @param[in] expression asserted expression.
|
||||
// @param[in] file Filename of the failed assertion.
|
||||
// @param[in] line Line number of the failed assertion.
|
||||
/// @see dtAssertFailSetCustom
|
||||
typedef void (dtAssertFailFunc)(const char* expression, const char* file, int line);
|
||||
|
||||
/// Sets the base custom assertion failure function to be used by Detour.
|
||||
/// @param[in] assertFailFunc The function to be invoked in case of failure of #dtAssert
|
||||
void dtAssertFailSetCustom(dtAssertFailFunc *assertFailFunc);
|
||||
|
||||
/// Gets the base custom assertion failure function to be used by Detour.
|
||||
dtAssertFailFunc* dtAssertFailGetCustom();
|
||||
|
||||
# include <assert.h>
|
||||
# define dtAssert(expression) \
|
||||
{ \
|
||||
dtAssertFailFunc* failFunc = dtAssertFailGetCustom(); \
|
||||
if(failFunc == NULL) { assert(expression); } \
|
||||
else if(!(expression)) { (*failFunc)(#expression, __FILE__, __LINE__); } \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // DETOURASSERT_H
|
||||
@@ -0,0 +1,550 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef DETOURCOMMON_H
|
||||
#define DETOURCOMMON_H
|
||||
|
||||
#include "DetourMath.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
@defgroup detour Detour
|
||||
|
||||
Members in this module are used to create, manipulate, and query navigation
|
||||
meshes.
|
||||
|
||||
@note This is a summary list of members. Use the index or search
|
||||
feature to find minor members.
|
||||
*/
|
||||
|
||||
/// @name General helper functions
|
||||
/// @{
|
||||
|
||||
/// Used to ignore a function parameter. VS complains about unused parameters
|
||||
/// and this silences the warning.
|
||||
/// @param [in] _ Unused parameter
|
||||
template<class T> void dtIgnoreUnused(const T&) { }
|
||||
|
||||
/// Swaps the values of the two parameters.
|
||||
/// @param[in,out] a Value A
|
||||
/// @param[in,out] b Value B
|
||||
template<class T> inline void dtSwap(T& a, T& b) { T t = a; a = b; b = t; }
|
||||
|
||||
/// Returns the minimum of two values.
|
||||
/// @param[in] a Value A
|
||||
/// @param[in] b Value B
|
||||
/// @return The minimum of the two values.
|
||||
template<class T> inline T dtMin(T a, T b) { return a < b ? a : b; }
|
||||
|
||||
/// Returns the maximum of two values.
|
||||
/// @param[in] a Value A
|
||||
/// @param[in] b Value B
|
||||
/// @return The maximum of the two values.
|
||||
template<class T> inline T dtMax(T a, T b) { return a > b ? a : b; }
|
||||
|
||||
/// Returns the absolute value.
|
||||
/// @param[in] a The value.
|
||||
/// @return The absolute value of the specified value.
|
||||
template<class T> inline T dtAbs(T a) { return a < 0 ? -a : a; }
|
||||
|
||||
/// Returns the square of the value.
|
||||
/// @param[in] a The value.
|
||||
/// @return The square of the value.
|
||||
template<class T> inline T dtSqr(T a) { return a*a; }
|
||||
|
||||
/// Clamps the value to the specified range.
|
||||
/// @param[in] v The value to clamp.
|
||||
/// @param[in] mn The minimum permitted return value.
|
||||
/// @param[in] mx The maximum permitted return value.
|
||||
/// @return The value, clamped to the specified range.
|
||||
template<class T> inline T dtClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); }
|
||||
|
||||
/// @}
|
||||
/// @name Vector helper functions.
|
||||
/// @{
|
||||
|
||||
/// Derives the cross product of two vectors. (@p v1 x @p v2)
|
||||
/// @param[out] dest The cross product. [(x, y, z)]
|
||||
/// @param[in] v1 A Vector [(x, y, z)]
|
||||
/// @param[in] v2 A vector [(x, y, z)]
|
||||
inline void dtVcross(float* dest, const float* v1, const float* v2)
|
||||
{
|
||||
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||
dest[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||
}
|
||||
|
||||
/// Derives the dot product of two vectors. (@p v1 . @p v2)
|
||||
/// @param[in] v1 A Vector [(x, y, z)]
|
||||
/// @param[in] v2 A vector [(x, y, z)]
|
||||
/// @return The dot product.
|
||||
inline float dtVdot(const float* v1, const float* v2)
|
||||
{
|
||||
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
||||
}
|
||||
|
||||
/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s))
|
||||
/// @param[out] dest The result vector. [(x, y, z)]
|
||||
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||
/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
|
||||
/// @param[in] s The amount to scale @p v2 by before adding to @p v1.
|
||||
inline void dtVmad(float* dest, const float* v1, const float* v2, const float s)
|
||||
{
|
||||
dest[0] = v1[0]+v2[0]*s;
|
||||
dest[1] = v1[1]+v2[1]*s;
|
||||
dest[2] = v1[2]+v2[2]*s;
|
||||
}
|
||||
|
||||
/// Performs a linear interpolation between two vectors. (@p v1 toward @p v2)
|
||||
/// @param[out] dest The result vector. [(x, y, x)]
|
||||
/// @param[in] v1 The starting vector.
|
||||
/// @param[in] v2 The destination vector.
|
||||
/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
|
||||
inline void dtVlerp(float* dest, const float* v1, const float* v2, const float t)
|
||||
{
|
||||
dest[0] = v1[0]+(v2[0]-v1[0])*t;
|
||||
dest[1] = v1[1]+(v2[1]-v1[1])*t;
|
||||
dest[2] = v1[2]+(v2[2]-v1[2])*t;
|
||||
}
|
||||
|
||||
/// Performs a vector addition. (@p v1 + @p v2)
|
||||
/// @param[out] dest The result vector. [(x, y, z)]
|
||||
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||
/// @param[in] v2 The vector to add to @p v1. [(x, y, z)]
|
||||
inline void dtVadd(float* dest, const float* v1, const float* v2)
|
||||
{
|
||||
dest[0] = v1[0]+v2[0];
|
||||
dest[1] = v1[1]+v2[1];
|
||||
dest[2] = v1[2]+v2[2];
|
||||
}
|
||||
|
||||
/// Performs a vector subtraction. (@p v1 - @p v2)
|
||||
/// @param[out] dest The result vector. [(x, y, z)]
|
||||
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||
/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)]
|
||||
inline void dtVsub(float* dest, const float* v1, const float* v2)
|
||||
{
|
||||
dest[0] = v1[0]-v2[0];
|
||||
dest[1] = v1[1]-v2[1];
|
||||
dest[2] = v1[2]-v2[2];
|
||||
}
|
||||
|
||||
/// Scales the vector by the specified value. (@p v * @p t)
|
||||
/// @param[out] dest The result vector. [(x, y, z)]
|
||||
/// @param[in] v The vector to scale. [(x, y, z)]
|
||||
/// @param[in] t The scaling factor.
|
||||
inline void dtVscale(float* dest, const float* v, const float t)
|
||||
{
|
||||
dest[0] = v[0]*t;
|
||||
dest[1] = v[1]*t;
|
||||
dest[2] = v[2]*t;
|
||||
}
|
||||
|
||||
/// Selects the minimum value of each element from the specified vectors.
|
||||
/// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)]
|
||||
/// @param[in] v A vector. [(x, y, z)]
|
||||
inline void dtVmin(float* mn, const float* v)
|
||||
{
|
||||
mn[0] = dtMin(mn[0], v[0]);
|
||||
mn[1] = dtMin(mn[1], v[1]);
|
||||
mn[2] = dtMin(mn[2], v[2]);
|
||||
}
|
||||
|
||||
/// Selects the maximum value of each element from the specified vectors.
|
||||
/// @param[in,out] mx A vector. (Will be updated with the result.) [(x, y, z)]
|
||||
/// @param[in] v A vector. [(x, y, z)]
|
||||
inline void dtVmax(float* mx, const float* v)
|
||||
{
|
||||
mx[0] = dtMax(mx[0], v[0]);
|
||||
mx[1] = dtMax(mx[1], v[1]);
|
||||
mx[2] = dtMax(mx[2], v[2]);
|
||||
}
|
||||
|
||||
/// Sets the vector elements to the specified values.
|
||||
/// @param[out] dest The result vector. [(x, y, z)]
|
||||
/// @param[in] x The x-value of the vector.
|
||||
/// @param[in] y The y-value of the vector.
|
||||
/// @param[in] z The z-value of the vector.
|
||||
inline void dtVset(float* dest, const float x, const float y, const float z)
|
||||
{
|
||||
dest[0] = x; dest[1] = y; dest[2] = z;
|
||||
}
|
||||
|
||||
/// Performs a vector copy.
|
||||
/// @param[out] dest The result. [(x, y, z)]
|
||||
/// @param[in] a The vector to copy. [(x, y, z)]
|
||||
inline void dtVcopy(float* dest, const float* a)
|
||||
{
|
||||
dest[0] = a[0];
|
||||
dest[1] = a[1];
|
||||
dest[2] = a[2];
|
||||
}
|
||||
|
||||
/// Derives the scalar length of the vector.
|
||||
/// @param[in] v The vector. [(x, y, z)]
|
||||
/// @return The scalar length of the vector.
|
||||
inline float dtVlen(const float* v)
|
||||
{
|
||||
return dtMathSqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||
}
|
||||
|
||||
/// Derives the square of the scalar length of the vector. (len * len)
|
||||
/// @param[in] v The vector. [(x, y, z)]
|
||||
/// @return The square of the scalar length of the vector.
|
||||
inline float dtVlenSqr(const float* v)
|
||||
{
|
||||
return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
||||
}
|
||||
|
||||
/// Returns the distance between two points.
|
||||
/// @param[in] v1 A point. [(x, y, z)]
|
||||
/// @param[in] v2 A point. [(x, y, z)]
|
||||
/// @return The distance between the two points.
|
||||
inline float dtVdist(const float* v1, const float* v2)
|
||||
{
|
||||
const float dx = v2[0] - v1[0];
|
||||
const float dy = v2[1] - v1[1];
|
||||
const float dz = v2[2] - v1[2];
|
||||
return dtMathSqrtf(dx*dx + dy*dy + dz*dz);
|
||||
}
|
||||
|
||||
/// Returns the square of the distance between two points.
|
||||
/// @param[in] v1 A point. [(x, y, z)]
|
||||
/// @param[in] v2 A point. [(x, y, z)]
|
||||
/// @return The square of the distance between the two points.
|
||||
inline float dtVdistSqr(const float* v1, const float* v2)
|
||||
{
|
||||
const float dx = v2[0] - v1[0];
|
||||
const float dy = v2[1] - v1[1];
|
||||
const float dz = v2[2] - v1[2];
|
||||
return dx*dx + dy*dy + dz*dz;
|
||||
}
|
||||
|
||||
/// Derives the distance between the specified points on the xz-plane.
|
||||
/// @param[in] v1 A point. [(x, y, z)]
|
||||
/// @param[in] v2 A point. [(x, y, z)]
|
||||
/// @return The distance between the point on the xz-plane.
|
||||
///
|
||||
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||
inline float dtVdist2D(const float* v1, const float* v2)
|
||||
{
|
||||
const float dx = v2[0] - v1[0];
|
||||
const float dz = v2[2] - v1[2];
|
||||
return dtMathSqrtf(dx*dx + dz*dz);
|
||||
}
|
||||
|
||||
/// Derives the square of the distance between the specified points on the xz-plane.
|
||||
/// @param[in] v1 A point. [(x, y, z)]
|
||||
/// @param[in] v2 A point. [(x, y, z)]
|
||||
/// @return The square of the distance between the point on the xz-plane.
|
||||
inline float dtVdist2DSqr(const float* v1, const float* v2)
|
||||
{
|
||||
const float dx = v2[0] - v1[0];
|
||||
const float dz = v2[2] - v1[2];
|
||||
return dx*dx + dz*dz;
|
||||
}
|
||||
|
||||
/// Normalizes the vector.
|
||||
/// @param[in,out] v The vector to normalize. [(x, y, z)]
|
||||
inline void dtVnormalize(float* v)
|
||||
{
|
||||
float d = 1.0f / dtMathSqrtf(dtSqr(v[0]) + dtSqr(v[1]) + dtSqr(v[2]));
|
||||
v[0] *= d;
|
||||
v[1] *= d;
|
||||
v[2] *= d;
|
||||
}
|
||||
|
||||
/// Performs a 'sloppy' colocation check of the specified points.
|
||||
/// @param[in] p0 A point. [(x, y, z)]
|
||||
/// @param[in] p1 A point. [(x, y, z)]
|
||||
/// @return True if the points are considered to be at the same location.
|
||||
///
|
||||
/// Basically, this function will return true if the specified points are
|
||||
/// close enough to eachother to be considered colocated.
|
||||
inline bool dtVequal(const float* p0, const float* p1)
|
||||
{
|
||||
static const float thr = dtSqr(1.0f/16384.0f);
|
||||
const float d = dtVdistSqr(p0, p1);
|
||||
return d < thr;
|
||||
}
|
||||
|
||||
/// Derives the dot product of two vectors on the xz-plane. (@p u . @p v)
|
||||
/// @param[in] u A vector [(x, y, z)]
|
||||
/// @param[in] v A vector [(x, y, z)]
|
||||
/// @return The dot product on the xz-plane.
|
||||
///
|
||||
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||
inline float dtVdot2D(const float* u, const float* v)
|
||||
{
|
||||
return u[0]*v[0] + u[2]*v[2];
|
||||
}
|
||||
|
||||
/// Derives the xz-plane 2D perp product of the two vectors. (uz*vx - ux*vz)
|
||||
/// @param[in] u The LHV vector [(x, y, z)]
|
||||
/// @param[in] v The RHV vector [(x, y, z)]
|
||||
/// @return The dot product on the xz-plane.
|
||||
///
|
||||
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||
inline float dtVperp2D(const float* u, const float* v)
|
||||
{
|
||||
return u[2]*v[0] - u[0]*v[2];
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Computational geometry helper functions.
|
||||
/// @{
|
||||
|
||||
/// Derives the signed xz-plane area of the triangle ABC, or the relationship of line AB to point C.
|
||||
/// @param[in] a Vertex A. [(x, y, z)]
|
||||
/// @param[in] b Vertex B. [(x, y, z)]
|
||||
/// @param[in] c Vertex C. [(x, y, z)]
|
||||
/// @return The signed xz-plane area of the triangle.
|
||||
inline float dtTriArea2D(const float* a, const float* b, const float* c)
|
||||
{
|
||||
const float abx = b[0] - a[0];
|
||||
const float abz = b[2] - a[2];
|
||||
const float acx = c[0] - a[0];
|
||||
const float acz = c[2] - a[2];
|
||||
return acx*abz - abx*acz;
|
||||
}
|
||||
|
||||
/// Determines if two axis-aligned bounding boxes overlap.
|
||||
/// @param[in] amin Minimum bounds of box A. [(x, y, z)]
|
||||
/// @param[in] amax Maximum bounds of box A. [(x, y, z)]
|
||||
/// @param[in] bmin Minimum bounds of box B. [(x, y, z)]
|
||||
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||
/// @return True if the two AABB's overlap.
|
||||
/// @see dtOverlapBounds
|
||||
inline bool dtOverlapQuantBounds(const unsigned short amin[3], const unsigned short amax[3],
|
||||
const unsigned short bmin[3], const unsigned short bmax[3])
|
||||
{
|
||||
bool overlap = true;
|
||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
||||
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
||||
return overlap;
|
||||
}
|
||||
|
||||
/// Determines if two axis-aligned bounding boxes overlap.
|
||||
/// @param[in] amin Minimum bounds of box A. [(x, y, z)]
|
||||
/// @param[in] amax Maximum bounds of box A. [(x, y, z)]
|
||||
/// @param[in] bmin Minimum bounds of box B. [(x, y, z)]
|
||||
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||
/// @return True if the two AABB's overlap.
|
||||
/// @see dtOverlapQuantBounds
|
||||
inline bool dtOverlapBounds(const float* amin, const float* amax,
|
||||
const float* bmin, const float* bmax)
|
||||
{
|
||||
bool overlap = true;
|
||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
||||
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
||||
return overlap;
|
||||
}
|
||||
|
||||
/// Derives the closest point on a triangle from the specified reference point.
|
||||
/// @param[out] closest The closest point on the triangle.
|
||||
/// @param[in] p The reference point from which to test. [(x, y, z)]
|
||||
/// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
|
||||
/// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
|
||||
/// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
|
||||
void dtClosestPtPointTriangle(float* closest, const float* p,
|
||||
const float* a, const float* b, const float* c);
|
||||
|
||||
/// Derives the y-axis height of the closest point on the triangle from the specified reference point.
|
||||
/// @param[in] p The reference point from which to test. [(x, y, z)]
|
||||
/// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
|
||||
/// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
|
||||
/// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
|
||||
/// @param[out] h The resulting height.
|
||||
bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h);
|
||||
|
||||
bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
|
||||
const float* verts, int nverts,
|
||||
float& tmin, float& tmax,
|
||||
int& segMin, int& segMax);
|
||||
|
||||
bool dtIntersectSegSeg2D(const float* ap, const float* aq,
|
||||
const float* bp, const float* bq,
|
||||
float& s, float& t);
|
||||
|
||||
/// Determines if the specified point is inside the convex polygon on the xz-plane.
|
||||
/// @param[in] pt The point to check. [(x, y, z)]
|
||||
/// @param[in] verts The polygon vertices. [(x, y, z) * @p nverts]
|
||||
/// @param[in] nverts The number of vertices. [Limit: >= 3]
|
||||
/// @return True if the point is inside the polygon.
|
||||
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts);
|
||||
|
||||
bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
|
||||
float* ed, float* et);
|
||||
|
||||
float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t);
|
||||
|
||||
/// Derives the centroid of a convex polygon.
|
||||
/// @param[out] tc The centroid of the polgyon. [(x, y, z)]
|
||||
/// @param[in] idx The polygon indices. [(vertIndex) * @p nidx]
|
||||
/// @param[in] nidx The number of indices in the polygon. [Limit: >= 3]
|
||||
/// @param[in] verts The polygon vertices. [(x, y, z) * vertCount]
|
||||
void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts);
|
||||
|
||||
/// Determines if the two convex polygons overlap on the xz-plane.
|
||||
/// @param[in] polya Polygon A vertices. [(x, y, z) * @p npolya]
|
||||
/// @param[in] npolya The number of vertices in polygon A.
|
||||
/// @param[in] polyb Polygon B vertices. [(x, y, z) * @p npolyb]
|
||||
/// @param[in] npolyb The number of vertices in polygon B.
|
||||
/// @return True if the two polygons overlap.
|
||||
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
||||
const float* polyb, const int npolyb);
|
||||
|
||||
/// @}
|
||||
/// @name Miscellanious functions.
|
||||
/// @{
|
||||
|
||||
inline unsigned int dtNextPow2(unsigned int v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return v;
|
||||
}
|
||||
|
||||
inline unsigned int dtIlog2(unsigned int v)
|
||||
{
|
||||
unsigned int r;
|
||||
unsigned int shift;
|
||||
r = (v > 0xffff) << 4; v >>= r;
|
||||
shift = (v > 0xff) << 3; v >>= shift; r |= shift;
|
||||
shift = (v > 0xf) << 2; v >>= shift; r |= shift;
|
||||
shift = (v > 0x3) << 1; v >>= shift; r |= shift;
|
||||
r |= (v >> 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline int dtAlign4(int x) { return (x+3) & ~3; }
|
||||
|
||||
inline int dtOppositeTile(int side) { return (side+4) & 0x7; }
|
||||
|
||||
inline void dtSwapByte(unsigned char* a, unsigned char* b)
|
||||
{
|
||||
unsigned char tmp = *a;
|
||||
*a = *b;
|
||||
*b = tmp;
|
||||
}
|
||||
|
||||
inline void dtSwapEndian(unsigned short* v)
|
||||
{
|
||||
unsigned char* x = (unsigned char*)v;
|
||||
dtSwapByte(x+0, x+1);
|
||||
}
|
||||
|
||||
inline void dtSwapEndian(short* v)
|
||||
{
|
||||
unsigned char* x = (unsigned char*)v;
|
||||
dtSwapByte(x+0, x+1);
|
||||
}
|
||||
|
||||
inline void dtSwapEndian(unsigned int* v)
|
||||
{
|
||||
unsigned char* x = (unsigned char*)v;
|
||||
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||
}
|
||||
|
||||
inline void dtSwapEndian(int* v)
|
||||
{
|
||||
unsigned char* x = (unsigned char*)v;
|
||||
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||
}
|
||||
|
||||
inline void dtSwapEndian(float* v)
|
||||
{
|
||||
unsigned char* x = (unsigned char*)v;
|
||||
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||
}
|
||||
|
||||
void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
|
||||
const float s, const float t, float* out);
|
||||
|
||||
template<typename TypeToRetrieveAs>
|
||||
TypeToRetrieveAs* dtGetThenAdvanceBufferPointer(const unsigned char*& buffer, const size_t distanceToAdvance)
|
||||
{
|
||||
TypeToRetrieveAs* returnPointer = reinterpret_cast<TypeToRetrieveAs*>(buffer);
|
||||
buffer += distanceToAdvance;
|
||||
return returnPointer;
|
||||
}
|
||||
|
||||
template<typename TypeToRetrieveAs>
|
||||
TypeToRetrieveAs* dtGetThenAdvanceBufferPointer(unsigned char*& buffer, const size_t distanceToAdvance)
|
||||
{
|
||||
TypeToRetrieveAs* returnPointer = reinterpret_cast<TypeToRetrieveAs*>(buffer);
|
||||
buffer += distanceToAdvance;
|
||||
return returnPointer;
|
||||
}
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
#endif // DETOURCOMMON_H
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This section contains detailed documentation for members that don't have
|
||||
// a source file. It reduces clutter in the main section of the header.
|
||||
|
||||
/**
|
||||
|
||||
@fn float dtTriArea2D(const float* a, const float* b, const float* c)
|
||||
@par
|
||||
|
||||
The vertices are projected onto the xz-plane, so the y-values are ignored.
|
||||
|
||||
This is a low cost function than can be used for various purposes. Its main purpose
|
||||
is for point/line relationship testing.
|
||||
|
||||
In all cases: A value of zero indicates that all vertices are collinear or represent the same point.
|
||||
(On the xz-plane.)
|
||||
|
||||
When used for point/line relationship tests, AB usually represents a line against which
|
||||
the C point is to be tested. In this case:
|
||||
|
||||
A positive value indicates that point C is to the left of line AB, looking from A toward B.<br/>
|
||||
A negative value indicates that point C is to the right of lineAB, looking from A toward B.
|
||||
|
||||
When used for evaluating a triangle:
|
||||
|
||||
The absolute value of the return value is two times the area of the triangle when it is
|
||||
projected onto the xz-plane.
|
||||
|
||||
A positive return value indicates:
|
||||
|
||||
<ul>
|
||||
<li>The vertices are wrapped in the normal Detour wrap direction.</li>
|
||||
<li>The triangle's 3D face normal is in the general up direction.</li>
|
||||
</ul>
|
||||
|
||||
A negative return value indicates:
|
||||
|
||||
<ul>
|
||||
<li>The vertices are reverse wrapped. (Wrapped opposite the normal Detour wrap direction.)</li>
|
||||
<li>The triangle's 3D face normal is in the general down direction.</li>
|
||||
</ul>
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
@defgroup detour Detour
|
||||
|
||||
Members in this module are wrappers around the standard math library
|
||||
*/
|
||||
|
||||
#ifndef DETOURMATH_H
|
||||
#define DETOURMATH_H
|
||||
|
||||
#include <math.h>
|
||||
|
||||
inline float dtMathFabsf(float x) { return fabsf(x); }
|
||||
inline float dtMathSqrtf(float x) { return sqrtf(x); }
|
||||
inline float dtMathFloorf(float x) { return floorf(x); }
|
||||
inline float dtMathCeilf(float x) { return ceilf(x); }
|
||||
inline float dtMathCosf(float x) { return cosf(x); }
|
||||
inline float dtMathSinf(float x) { return sinf(x); }
|
||||
inline float dtMathAtan2f(float y, float x) { return atan2f(y, x); }
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,765 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef DETOURNAVMESH_H
|
||||
#define DETOURNAVMESH_H
|
||||
|
||||
#include "DetourAlloc.h"
|
||||
#include "DetourStatus.h"
|
||||
|
||||
// Undefine (or define in a build cofnig) the following line to use 64bit polyref.
|
||||
// Generally not needed, useful for very large worlds.
|
||||
// Note: tiles build using 32bit refs are not compatible with 64bit refs!
|
||||
//#define DT_POLYREF64 1
|
||||
|
||||
#ifdef DT_POLYREF64
|
||||
// TODO: figure out a multiplatform version of uint64_t
|
||||
// - maybe: https://code.google.com/p/msinttypes/
|
||||
// - or: http://www.azillionmonkeys.com/qed/pstdint.h
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
// Note: If you want to use 64-bit refs, change the types of both dtPolyRef & dtTileRef.
|
||||
// It is also recommended that you change dtHashRef() to a proper 64-bit hash.
|
||||
|
||||
/// A handle to a polygon within a navigation mesh tile.
|
||||
/// @ingroup detour
|
||||
#ifdef DT_POLYREF64
|
||||
static const unsigned int DT_SALT_BITS = 16;
|
||||
static const unsigned int DT_TILE_BITS = 28;
|
||||
static const unsigned int DT_POLY_BITS = 20;
|
||||
typedef uint64_t dtPolyRef;
|
||||
#else
|
||||
typedef unsigned int dtPolyRef;
|
||||
#endif
|
||||
|
||||
/// A handle to a tile within a navigation mesh.
|
||||
/// @ingroup detour
|
||||
#ifdef DT_POLYREF64
|
||||
typedef uint64_t dtTileRef;
|
||||
#else
|
||||
typedef unsigned int dtTileRef;
|
||||
#endif
|
||||
|
||||
/// The maximum number of vertices per navigation polygon.
|
||||
/// @ingroup detour
|
||||
static const int DT_VERTS_PER_POLYGON = 6;
|
||||
|
||||
/// @{
|
||||
/// @name Tile Serialization Constants
|
||||
/// These constants are used to detect whether a navigation tile's data
|
||||
/// and state format is compatible with the current build.
|
||||
///
|
||||
|
||||
/// A magic number used to detect compatibility of navigation tile data.
|
||||
static const int DT_NAVMESH_MAGIC = 'D'<<24 | 'N'<<16 | 'A'<<8 | 'V';
|
||||
|
||||
/// A version number used to detect compatibility of navigation tile data.
|
||||
static const int DT_NAVMESH_VERSION = 7;
|
||||
|
||||
/// A magic number used to detect the compatibility of navigation tile states.
|
||||
static const int DT_NAVMESH_STATE_MAGIC = 'D'<<24 | 'N'<<16 | 'M'<<8 | 'S';
|
||||
|
||||
/// A version number used to detect compatibility of navigation tile states.
|
||||
static const int DT_NAVMESH_STATE_VERSION = 1;
|
||||
|
||||
/// @}
|
||||
|
||||
/// A flag that indicates that an entity links to an external entity.
|
||||
/// (E.g. A polygon edge is a portal that links to another polygon.)
|
||||
static const unsigned short DT_EXT_LINK = 0x8000;
|
||||
|
||||
/// A value that indicates the entity does not link to anything.
|
||||
static const unsigned int DT_NULL_LINK = 0xffffffff;
|
||||
|
||||
/// A flag that indicates that an off-mesh connection can be traversed in both directions. (Is bidirectional.)
|
||||
static const unsigned int DT_OFFMESH_CON_BIDIR = 1;
|
||||
|
||||
/// The maximum number of user defined area ids.
|
||||
/// @ingroup detour
|
||||
static const int DT_MAX_AREAS = 64;
|
||||
|
||||
/// Tile flags used for various functions and fields.
|
||||
/// For an example, see dtNavMesh::addTile().
|
||||
enum dtTileFlags
|
||||
{
|
||||
/// The navigation mesh owns the tile memory and is responsible for freeing it.
|
||||
DT_TILE_FREE_DATA = 0x01,
|
||||
};
|
||||
|
||||
/// Vertex flags returned by dtNavMeshQuery::findStraightPath.
|
||||
enum dtStraightPathFlags
|
||||
{
|
||||
DT_STRAIGHTPATH_START = 0x01, ///< The vertex is the start position in the path.
|
||||
DT_STRAIGHTPATH_END = 0x02, ///< The vertex is the end position in the path.
|
||||
DT_STRAIGHTPATH_OFFMESH_CONNECTION = 0x04, ///< The vertex is the start of an off-mesh connection.
|
||||
};
|
||||
|
||||
/// Options for dtNavMeshQuery::findStraightPath.
|
||||
enum dtStraightPathOptions
|
||||
{
|
||||
DT_STRAIGHTPATH_AREA_CROSSINGS = 0x01, ///< Add a vertex at every polygon edge crossing where area changes.
|
||||
DT_STRAIGHTPATH_ALL_CROSSINGS = 0x02, ///< Add a vertex at every polygon edge crossing.
|
||||
};
|
||||
|
||||
|
||||
/// Options for dtNavMeshQuery::initSlicedFindPath and updateSlicedFindPath
|
||||
enum dtFindPathOptions
|
||||
{
|
||||
DT_FINDPATH_ANY_ANGLE = 0x02, ///< use raycasts during pathfind to "shortcut" (raycast still consider costs)
|
||||
};
|
||||
|
||||
/// Options for dtNavMeshQuery::raycast
|
||||
enum dtRaycastOptions
|
||||
{
|
||||
DT_RAYCAST_USE_COSTS = 0x01, ///< Raycast should calculate movement cost along the ray and fill RaycastHit::cost
|
||||
};
|
||||
|
||||
|
||||
/// Limit raycasting during any angle pahfinding
|
||||
/// The limit is given as a multiple of the character radius
|
||||
static const float DT_RAY_CAST_LIMIT_PROPORTIONS = 50.0f;
|
||||
|
||||
/// Flags representing the type of a navigation mesh polygon.
|
||||
enum dtPolyTypes
|
||||
{
|
||||
/// The polygon is a standard convex polygon that is part of the surface of the mesh.
|
||||
DT_POLYTYPE_GROUND = 0,
|
||||
/// The polygon is an off-mesh connection consisting of two vertices.
|
||||
DT_POLYTYPE_OFFMESH_CONNECTION = 1,
|
||||
};
|
||||
|
||||
|
||||
/// Defines a polygon within a dtMeshTile object.
|
||||
/// @ingroup detour
|
||||
struct dtPoly
|
||||
{
|
||||
/// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.)
|
||||
unsigned int firstLink;
|
||||
|
||||
/// The indices of the polygon's vertices.
|
||||
/// The actual vertices are located in dtMeshTile::verts.
|
||||
unsigned short verts[DT_VERTS_PER_POLYGON];
|
||||
|
||||
/// Packed data representing neighbor polygons references and flags for each edge.
|
||||
unsigned short neis[DT_VERTS_PER_POLYGON];
|
||||
|
||||
/// The user defined polygon flags.
|
||||
unsigned short flags;
|
||||
|
||||
/// The number of vertices in the polygon.
|
||||
unsigned char vertCount;
|
||||
|
||||
/// The bit packed area id and polygon type.
|
||||
/// @note Use the structure's set and get methods to acess this value.
|
||||
unsigned char areaAndtype;
|
||||
|
||||
/// Sets the user defined area id. [Limit: < #DT_MAX_AREAS]
|
||||
inline void setArea(unsigned char a) { areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f); }
|
||||
|
||||
/// Sets the polygon type. (See: #dtPolyTypes.)
|
||||
inline void setType(unsigned char t) { areaAndtype = (areaAndtype & 0x3f) | (t << 6); }
|
||||
|
||||
/// Gets the user defined area id.
|
||||
inline unsigned char getArea() const { return areaAndtype & 0x3f; }
|
||||
|
||||
/// Gets the polygon type. (See: #dtPolyTypes)
|
||||
inline unsigned char getType() const { return areaAndtype >> 6; }
|
||||
};
|
||||
|
||||
/// Defines the location of detail sub-mesh data within a dtMeshTile.
|
||||
struct dtPolyDetail
|
||||
{
|
||||
unsigned int vertBase; ///< The offset of the vertices in the dtMeshTile::detailVerts array.
|
||||
unsigned int triBase; ///< The offset of the triangles in the dtMeshTile::detailTris array.
|
||||
unsigned char vertCount; ///< The number of vertices in the sub-mesh.
|
||||
unsigned char triCount; ///< The number of triangles in the sub-mesh.
|
||||
};
|
||||
|
||||
/// Defines a link between polygons.
|
||||
/// @note This structure is rarely if ever used by the end user.
|
||||
/// @see dtMeshTile
|
||||
struct dtLink
|
||||
{
|
||||
dtPolyRef ref; ///< Neighbour reference. (The neighbor that is linked to.)
|
||||
unsigned int next; ///< Index of the next link.
|
||||
unsigned char edge; ///< Index of the polygon edge that owns this link.
|
||||
unsigned char side; ///< If a boundary link, defines on which side the link is.
|
||||
unsigned char bmin; ///< If a boundary link, defines the minimum sub-edge area.
|
||||
unsigned char bmax; ///< If a boundary link, defines the maximum sub-edge area.
|
||||
};
|
||||
|
||||
/// Bounding volume node.
|
||||
/// @note This structure is rarely if ever used by the end user.
|
||||
/// @see dtMeshTile
|
||||
struct dtBVNode
|
||||
{
|
||||
unsigned short bmin[3]; ///< Minimum bounds of the node's AABB. [(x, y, z)]
|
||||
unsigned short bmax[3]; ///< Maximum bounds of the node's AABB. [(x, y, z)]
|
||||
int i; ///< The node's index. (Negative for escape sequence.)
|
||||
};
|
||||
|
||||
/// Defines an navigation mesh off-mesh connection within a dtMeshTile object.
|
||||
/// An off-mesh connection is a user defined traversable connection made up to two vertices.
|
||||
struct dtOffMeshConnection
|
||||
{
|
||||
/// The endpoints of the connection. [(ax, ay, az, bx, by, bz)]
|
||||
float pos[6];
|
||||
|
||||
/// The radius of the endpoints. [Limit: >= 0]
|
||||
float rad;
|
||||
|
||||
/// The polygon reference of the connection within the tile.
|
||||
unsigned short poly;
|
||||
|
||||
/// Link flags.
|
||||
/// @note These are not the connection's user defined flags. Those are assigned via the
|
||||
/// connection's dtPoly definition. These are link flags used for internal purposes.
|
||||
unsigned char flags;
|
||||
|
||||
/// End point side.
|
||||
unsigned char side;
|
||||
|
||||
/// The id of the offmesh connection. (User assigned when the navigation mesh is built.)
|
||||
unsigned int userId;
|
||||
};
|
||||
|
||||
/// Provides high level information related to a dtMeshTile object.
|
||||
/// @ingroup detour
|
||||
struct dtMeshHeader
|
||||
{
|
||||
int magic; ///< Tile magic number. (Used to identify the data format.)
|
||||
int version; ///< Tile data format version number.
|
||||
int x; ///< The x-position of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||
int y; ///< The y-position of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||
int layer; ///< The layer of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||
unsigned int userId; ///< The user defined id of the tile.
|
||||
int polyCount; ///< The number of polygons in the tile.
|
||||
int vertCount; ///< The number of vertices in the tile.
|
||||
int maxLinkCount; ///< The number of allocated links.
|
||||
int detailMeshCount; ///< The number of sub-meshes in the detail mesh.
|
||||
|
||||
/// The number of unique vertices in the detail mesh. (In addition to the polygon vertices.)
|
||||
int detailVertCount;
|
||||
|
||||
int detailTriCount; ///< The number of triangles in the detail mesh.
|
||||
int bvNodeCount; ///< The number of bounding volume nodes. (Zero if bounding volumes are disabled.)
|
||||
int offMeshConCount; ///< The number of off-mesh connections.
|
||||
int offMeshBase; ///< The index of the first polygon which is an off-mesh connection.
|
||||
float walkableHeight; ///< The height of the agents using the tile.
|
||||
float walkableRadius; ///< The radius of the agents using the tile.
|
||||
float walkableClimb; ///< The maximum climb height of the agents using the tile.
|
||||
float bmin[3]; ///< The minimum bounds of the tile's AABB. [(x, y, z)]
|
||||
float bmax[3]; ///< The maximum bounds of the tile's AABB. [(x, y, z)]
|
||||
|
||||
/// The bounding volume quantization factor.
|
||||
float bvQuantFactor;
|
||||
};
|
||||
|
||||
/// Defines a navigation mesh tile.
|
||||
/// @ingroup detour
|
||||
struct dtMeshTile
|
||||
{
|
||||
unsigned int salt; ///< Counter describing modifications to the tile.
|
||||
|
||||
unsigned int linksFreeList; ///< Index to the next free link.
|
||||
dtMeshHeader* header; ///< The tile header.
|
||||
dtPoly* polys; ///< The tile polygons. [Size: dtMeshHeader::polyCount]
|
||||
float* verts; ///< The tile vertices. [Size: dtMeshHeader::vertCount]
|
||||
dtLink* links; ///< The tile links. [Size: dtMeshHeader::maxLinkCount]
|
||||
dtPolyDetail* detailMeshes; ///< The tile's detail sub-meshes. [Size: dtMeshHeader::detailMeshCount]
|
||||
|
||||
/// The detail mesh's unique vertices. [(x, y, z) * dtMeshHeader::detailVertCount]
|
||||
float* detailVerts;
|
||||
|
||||
/// The detail mesh's triangles. [(vertA, vertB, vertC) * dtMeshHeader::detailTriCount]
|
||||
unsigned char* detailTris;
|
||||
|
||||
/// The tile bounding volume nodes. [Size: dtMeshHeader::bvNodeCount]
|
||||
/// (Will be null if bounding volumes are disabled.)
|
||||
dtBVNode* bvTree;
|
||||
|
||||
dtOffMeshConnection* offMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
|
||||
|
||||
unsigned char* data; ///< The tile data. (Not directly accessed under normal situations.)
|
||||
int dataSize; ///< Size of the tile data.
|
||||
int flags; ///< Tile flags. (See: #dtTileFlags)
|
||||
dtMeshTile* next; ///< The next free tile, or the next tile in the spatial grid.
|
||||
private:
|
||||
dtMeshTile(const dtMeshTile&);
|
||||
dtMeshTile& operator=(const dtMeshTile&);
|
||||
};
|
||||
|
||||
/// Configuration parameters used to define multi-tile navigation meshes.
|
||||
/// The values are used to allocate space during the initialization of a navigation mesh.
|
||||
/// @see dtNavMesh::init()
|
||||
/// @ingroup detour
|
||||
struct dtNavMeshParams
|
||||
{
|
||||
float orig[3]; ///< The world space origin of the navigation mesh's tile space. [(x, y, z)]
|
||||
float tileWidth; ///< The width of each tile. (Along the x-axis.)
|
||||
float tileHeight; ///< The height of each tile. (Along the z-axis.)
|
||||
int maxTiles; ///< The maximum number of tiles the navigation mesh can contain.
|
||||
int maxPolys; ///< The maximum number of polygons each tile can contain.
|
||||
};
|
||||
|
||||
/// A navigation mesh based on tiles of convex polygons.
|
||||
/// @ingroup detour
|
||||
class dtNavMesh
|
||||
{
|
||||
public:
|
||||
dtNavMesh();
|
||||
~dtNavMesh();
|
||||
|
||||
/// @{
|
||||
/// @name Initialization and Tile Management
|
||||
|
||||
/// Initializes the navigation mesh for tiled use.
|
||||
/// @param[in] params Initialization parameters.
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus init(const dtNavMeshParams* params);
|
||||
|
||||
/// Initializes the navigation mesh for single tile use.
|
||||
/// @param[in] data Data of the new tile. (See: #dtCreateNavMeshData)
|
||||
/// @param[in] dataSize The data size of the new tile.
|
||||
/// @param[in] flags The tile flags. (See: #dtTileFlags)
|
||||
/// @return The status flags for the operation.
|
||||
/// @see dtCreateNavMeshData
|
||||
dtStatus init(unsigned char* data, const int dataSize, const int flags);
|
||||
|
||||
/// The navigation mesh initialization params.
|
||||
const dtNavMeshParams* getParams() const;
|
||||
|
||||
/// Adds a tile to the navigation mesh.
|
||||
/// @param[in] data Data for the new tile mesh. (See: #dtCreateNavMeshData)
|
||||
/// @param[in] dataSize Data size of the new tile mesh.
|
||||
/// @param[in] flags Tile flags. (See: #dtTileFlags)
|
||||
/// @param[in] lastRef The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0]
|
||||
/// @param[out] result The tile reference. (If the tile was succesfully added.) [opt]
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result);
|
||||
|
||||
/// Removes the specified tile from the navigation mesh.
|
||||
/// @param[in] ref The reference of the tile to remove.
|
||||
/// @param[out] data Data associated with deleted tile.
|
||||
/// @param[out] dataSize Size of the data associated with deleted tile.
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus removeTile(dtTileRef ref, unsigned char** data, int* dataSize);
|
||||
|
||||
/// @}
|
||||
|
||||
/// @{
|
||||
/// @name Query Functions
|
||||
|
||||
/// Calculates the tile grid location for the specified world position.
|
||||
/// @param[in] pos The world position for the query. [(x, y, z)]
|
||||
/// @param[out] tx The tile's x-location. (x, y)
|
||||
/// @param[out] ty The tile's y-location. (x, y)
|
||||
void calcTileLoc(const float* pos, int* tx, int* ty) const;
|
||||
|
||||
/// Gets the tile at the specified grid location.
|
||||
/// @param[in] x The tile's x-location. (x, y, layer)
|
||||
/// @param[in] y The tile's y-location. (x, y, layer)
|
||||
/// @param[in] layer The tile's layer. (x, y, layer)
|
||||
/// @return The tile, or null if the tile does not exist.
|
||||
const dtMeshTile* getTileAt(const int x, const int y, const int layer) const;
|
||||
|
||||
/// Gets all tiles at the specified grid location. (All layers.)
|
||||
/// @param[in] x The tile's x-location. (x, y)
|
||||
/// @param[in] y The tile's y-location. (x, y)
|
||||
/// @param[out] tiles A pointer to an array of tiles that will hold the result.
|
||||
/// @param[in] maxTiles The maximum tiles the tiles parameter can hold.
|
||||
/// @return The number of tiles returned in the tiles array.
|
||||
int getTilesAt(const int x, const int y,
|
||||
dtMeshTile const** tiles, const int maxTiles) const;
|
||||
|
||||
/// Gets the tile reference for the tile at specified grid location.
|
||||
/// @param[in] x The tile's x-location. (x, y, layer)
|
||||
/// @param[in] y The tile's y-location. (x, y, layer)
|
||||
/// @param[in] layer The tile's layer. (x, y, layer)
|
||||
/// @return The tile reference of the tile, or 0 if there is none.
|
||||
dtTileRef getTileRefAt(int x, int y, int layer) const;
|
||||
|
||||
/// Gets the tile reference for the specified tile.
|
||||
/// @param[in] tile The tile.
|
||||
/// @return The tile reference of the tile.
|
||||
dtTileRef getTileRef(const dtMeshTile* tile) const;
|
||||
|
||||
/// Gets the tile for the specified tile reference.
|
||||
/// @param[in] ref The tile reference of the tile to retrieve.
|
||||
/// @return The tile for the specified reference, or null if the
|
||||
/// reference is invalid.
|
||||
const dtMeshTile* getTileByRef(dtTileRef ref) const;
|
||||
|
||||
/// The maximum number of tiles supported by the navigation mesh.
|
||||
/// @return The maximum number of tiles supported by the navigation mesh.
|
||||
int getMaxTiles() const;
|
||||
|
||||
/// Gets the tile at the specified index.
|
||||
/// @param[in] i The tile index. [Limit: 0 >= index < #getMaxTiles()]
|
||||
/// @return The tile at the specified index.
|
||||
const dtMeshTile* getTile(int i) const;
|
||||
|
||||
/// Gets the tile and polygon for the specified polygon reference.
|
||||
/// @param[in] ref The reference for the a polygon.
|
||||
/// @param[out] tile The tile containing the polygon.
|
||||
/// @param[out] poly The polygon.
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus getTileAndPolyByRef(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
||||
|
||||
/// Returns the tile and polygon for the specified polygon reference.
|
||||
/// @param[in] ref A known valid reference for a polygon.
|
||||
/// @param[out] tile The tile containing the polygon.
|
||||
/// @param[out] poly The polygon.
|
||||
void getTileAndPolyByRefUnsafe(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
||||
|
||||
/// Checks the validity of a polygon reference.
|
||||
/// @param[in] ref The polygon reference to check.
|
||||
/// @return True if polygon reference is valid for the navigation mesh.
|
||||
bool isValidPolyRef(dtPolyRef ref) const;
|
||||
|
||||
/// Gets the polygon reference for the tile's base polygon.
|
||||
/// @param[in] tile The tile.
|
||||
/// @return The polygon reference for the base polygon in the specified tile.
|
||||
dtPolyRef getPolyRefBase(const dtMeshTile* tile) const;
|
||||
|
||||
/// Gets the endpoints for an off-mesh connection, ordered by "direction of travel".
|
||||
/// @param[in] prevRef The reference of the polygon before the connection.
|
||||
/// @param[in] polyRef The reference of the off-mesh connection polygon.
|
||||
/// @param[out] startPos The start position of the off-mesh connection. [(x, y, z)]
|
||||
/// @param[out] endPos The end position of the off-mesh connection. [(x, y, z)]
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const;
|
||||
|
||||
/// Gets the specified off-mesh connection.
|
||||
/// @param[in] ref The polygon reference of the off-mesh connection.
|
||||
/// @return The specified off-mesh connection, or null if the polygon reference is not valid.
|
||||
const dtOffMeshConnection* getOffMeshConnectionByRef(dtPolyRef ref) const;
|
||||
|
||||
/// @}
|
||||
|
||||
/// @{
|
||||
/// @name State Management
|
||||
/// These functions do not effect #dtTileRef or #dtPolyRef's.
|
||||
|
||||
/// Sets the user defined flags for the specified polygon.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @param[in] flags The new flags for the polygon.
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus setPolyFlags(dtPolyRef ref, unsigned short flags);
|
||||
|
||||
/// Gets the user defined flags for the specified polygon.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @param[out] resultFlags The polygon flags.
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) const;
|
||||
|
||||
/// Sets the user defined area for the specified polygon.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @param[in] area The new area id for the polygon. [Limit: < #DT_MAX_AREAS]
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus setPolyArea(dtPolyRef ref, unsigned char area);
|
||||
|
||||
/// Gets the user defined area for the specified polygon.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @param[out] resultArea The area id for the polygon.
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus getPolyArea(dtPolyRef ref, unsigned char* resultArea) const;
|
||||
|
||||
/// Gets the size of the buffer required by #storeTileState to store the specified tile's state.
|
||||
/// @param[in] tile The tile.
|
||||
/// @return The size of the buffer required to store the state.
|
||||
int getTileStateSize(const dtMeshTile* tile) const;
|
||||
|
||||
/// Stores the non-structural state of the tile in the specified buffer. (Flags, area ids, etc.)
|
||||
/// @param[in] tile The tile.
|
||||
/// @param[out] data The buffer to store the tile's state in.
|
||||
/// @param[in] maxDataSize The size of the data buffer. [Limit: >= #getTileStateSize]
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus storeTileState(const dtMeshTile* tile, unsigned char* data, const int maxDataSize) const;
|
||||
|
||||
/// Restores the state of the tile.
|
||||
/// @param[in] tile The tile.
|
||||
/// @param[in] data The new state. (Obtained from #storeTileState.)
|
||||
/// @param[in] maxDataSize The size of the state within the data buffer.
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize);
|
||||
|
||||
/// @}
|
||||
|
||||
/// @{
|
||||
/// @name Encoding and Decoding
|
||||
/// These functions are generally meant for internal use only.
|
||||
|
||||
/// Derives a standard polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] salt The tile's salt value.
|
||||
/// @param[in] it The index of the tile.
|
||||
/// @param[in] ip The index of the polygon within the tile.
|
||||
inline dtPolyRef encodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const
|
||||
{
|
||||
#ifdef DT_POLYREF64
|
||||
return ((dtPolyRef)salt << (DT_POLY_BITS+DT_TILE_BITS)) | ((dtPolyRef)it << DT_POLY_BITS) | (dtPolyRef)ip;
|
||||
#else
|
||||
return ((dtPolyRef)salt << (m_polyBits+m_tileBits)) | ((dtPolyRef)it << m_polyBits) | (dtPolyRef)ip;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Decodes a standard polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference to decode.
|
||||
/// @param[out] salt The tile's salt value.
|
||||
/// @param[out] it The index of the tile.
|
||||
/// @param[out] ip The index of the polygon within the tile.
|
||||
/// @see #encodePolyId
|
||||
inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const
|
||||
{
|
||||
#ifdef DT_POLYREF64
|
||||
const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
|
||||
const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
|
||||
const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
|
||||
salt = (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
|
||||
it = (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
|
||||
ip = (unsigned int)(ref & polyMask);
|
||||
#else
|
||||
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
||||
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
||||
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
||||
salt = (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
||||
it = (unsigned int)((ref >> m_polyBits) & tileMask);
|
||||
ip = (unsigned int)(ref & polyMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Extracts a tile's salt value from the specified polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @see #encodePolyId
|
||||
inline unsigned int decodePolyIdSalt(dtPolyRef ref) const
|
||||
{
|
||||
#ifdef DT_POLYREF64
|
||||
const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
|
||||
return (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
|
||||
#else
|
||||
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
||||
return (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Extracts the tile's index from the specified polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @see #encodePolyId
|
||||
inline unsigned int decodePolyIdTile(dtPolyRef ref) const
|
||||
{
|
||||
#ifdef DT_POLYREF64
|
||||
const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
|
||||
return (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
|
||||
#else
|
||||
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
||||
return (unsigned int)((ref >> m_polyBits) & tileMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Extracts the polygon's index (within its tile) from the specified polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @see #encodePolyId
|
||||
inline unsigned int decodePolyIdPoly(dtPolyRef ref) const
|
||||
{
|
||||
#ifdef DT_POLYREF64
|
||||
const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
|
||||
return (unsigned int)(ref & polyMask);
|
||||
#else
|
||||
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
||||
return (unsigned int)(ref & polyMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
dtNavMesh(const dtNavMesh&);
|
||||
dtNavMesh& operator=(const dtNavMesh&);
|
||||
|
||||
/// Returns pointer to tile in the tile array.
|
||||
dtMeshTile* getTile(int i);
|
||||
|
||||
/// Returns neighbour tile based on side.
|
||||
int getTilesAt(const int x, const int y,
|
||||
dtMeshTile** tiles, const int maxTiles) const;
|
||||
|
||||
/// Returns neighbour tile based on side.
|
||||
int getNeighbourTilesAt(const int x, const int y, const int side,
|
||||
dtMeshTile** tiles, const int maxTiles) const;
|
||||
|
||||
/// Returns all polygons in neighbour tile based on portal defined by the segment.
|
||||
int findConnectingPolys(const float* va, const float* vb,
|
||||
const dtMeshTile* tile, int side,
|
||||
dtPolyRef* con, float* conarea, int maxcon) const;
|
||||
|
||||
/// Builds internal polygons links for a tile.
|
||||
void connectIntLinks(dtMeshTile* tile);
|
||||
/// Builds internal polygons links for a tile.
|
||||
void baseOffMeshLinks(dtMeshTile* tile);
|
||||
|
||||
/// Builds external polygon links for a tile.
|
||||
void connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||
/// Builds external polygon links for a tile.
|
||||
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||
|
||||
/// Removes external links at specified side.
|
||||
void unconnectLinks(dtMeshTile* tile, dtMeshTile* target);
|
||||
|
||||
|
||||
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed for off-mesh connection finding.
|
||||
|
||||
/// Queries polygons within a tile.
|
||||
int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
||||
dtPolyRef* polys, const int maxPolys) const;
|
||||
/// Find nearest polygon within a tile.
|
||||
dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center,
|
||||
const float* extents, float* nearestPt) const;
|
||||
/// Returns closest point on polygon.
|
||||
void closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
|
||||
|
||||
dtNavMeshParams m_params; ///< Current initialization params. TODO: do not store this info twice.
|
||||
float m_orig[3]; ///< Origin of the tile (0,0)
|
||||
float m_tileWidth, m_tileHeight; ///< Dimensions of each tile.
|
||||
int m_maxTiles; ///< Max number of tiles.
|
||||
int m_tileLutSize; ///< Tile hash lookup size (must be pot).
|
||||
int m_tileLutMask; ///< Tile hash lookup mask.
|
||||
|
||||
dtMeshTile** m_posLookup; ///< Tile hash lookup.
|
||||
dtMeshTile* m_nextFree; ///< Freelist of tiles.
|
||||
dtMeshTile* m_tiles; ///< List of tiles.
|
||||
|
||||
#ifndef DT_POLYREF64
|
||||
unsigned int m_saltBits; ///< Number of salt bits in the tile ID.
|
||||
unsigned int m_tileBits; ///< Number of tile bits in the tile ID.
|
||||
unsigned int m_polyBits; ///< Number of poly bits in the tile ID.
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Allocates a navigation mesh object using the Detour allocator.
|
||||
/// @return A navigation mesh that is ready for initialization, or null on failure.
|
||||
/// @ingroup detour
|
||||
dtNavMesh* dtAllocNavMesh();
|
||||
|
||||
/// Frees the specified navigation mesh object using the Detour allocator.
|
||||
/// @param[in] navmesh A navigation mesh allocated using #dtAllocNavMesh
|
||||
/// @ingroup detour
|
||||
void dtFreeNavMesh(dtNavMesh* navmesh);
|
||||
|
||||
#endif // DETOURNAVMESH_H
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This section contains detailed documentation for members that don't have
|
||||
// a source file. It reduces clutter in the main section of the header.
|
||||
|
||||
/**
|
||||
|
||||
@typedef dtPolyRef
|
||||
@par
|
||||
|
||||
Polygon references are subject to the same invalidate/preserve/restore
|
||||
rules that apply to #dtTileRef's. If the #dtTileRef for the polygon's
|
||||
tile changes, the polygon reference becomes invalid.
|
||||
|
||||
Changing a polygon's flags, area id, etc. does not impact its polygon
|
||||
reference.
|
||||
|
||||
@typedef dtTileRef
|
||||
@par
|
||||
|
||||
The following changes will invalidate a tile reference:
|
||||
|
||||
- The referenced tile has been removed from the navigation mesh.
|
||||
- The navigation mesh has been initialized using a different set
|
||||
of #dtNavMeshParams.
|
||||
|
||||
A tile reference is preserved/restored if the tile is added to a navigation
|
||||
mesh initialized with the original #dtNavMeshParams and is added at the
|
||||
original reference location. (E.g. The lastRef parameter is used with
|
||||
dtNavMesh::addTile.)
|
||||
|
||||
Basically, if the storage structure of a tile changes, its associated
|
||||
tile reference changes.
|
||||
|
||||
|
||||
@var unsigned short dtPoly::neis[DT_VERTS_PER_POLYGON]
|
||||
@par
|
||||
|
||||
Each entry represents data for the edge starting at the vertex of the same index.
|
||||
E.g. The entry at index n represents the edge data for vertex[n] to vertex[n+1].
|
||||
|
||||
A value of zero indicates the edge has no polygon connection. (It makes up the
|
||||
border of the navigation mesh.)
|
||||
|
||||
The information can be extracted as follows:
|
||||
@code
|
||||
neighborRef = neis[n] & 0xff; // Get the neighbor polygon reference.
|
||||
|
||||
if (neis[n] & #DT_EX_LINK)
|
||||
{
|
||||
// The edge is an external (portal) edge.
|
||||
}
|
||||
@endcode
|
||||
|
||||
@var float dtMeshHeader::bvQuantFactor
|
||||
@par
|
||||
|
||||
This value is used for converting between world and bounding volume coordinates.
|
||||
For example:
|
||||
@code
|
||||
const float cs = 1.0f / tile->header->bvQuantFactor;
|
||||
const dtBVNode* n = &tile->bvTree[i];
|
||||
if (n->i >= 0)
|
||||
{
|
||||
// This is a leaf node.
|
||||
float worldMinX = tile->header->bmin[0] + n->bmin[0]*cs;
|
||||
float worldMinY = tile->header->bmin[0] + n->bmin[1]*cs;
|
||||
// Etc...
|
||||
}
|
||||
@endcode
|
||||
|
||||
@struct dtMeshTile
|
||||
@par
|
||||
|
||||
Tiles generally only exist within the context of a dtNavMesh object.
|
||||
|
||||
Some tile content is optional. For example, a tile may not contain any
|
||||
off-mesh connections. In this case the associated pointer will be null.
|
||||
|
||||
If a detail mesh exists it will share vertices with the base polygon mesh.
|
||||
Only the vertices unique to the detail mesh will be stored in #detailVerts.
|
||||
|
||||
@warning Tiles returned by a dtNavMesh object are not guarenteed to be populated.
|
||||
For example: The tile at a location might not have been loaded yet, or may have been removed.
|
||||
In this case, pointers will be null. So if in doubt, check the polygon count in the
|
||||
tile's header to determine if a tile has polygons defined.
|
||||
|
||||
@var float dtOffMeshConnection::pos[6]
|
||||
@par
|
||||
|
||||
For a properly built navigation mesh, vertex A will always be within the bounds of the mesh.
|
||||
Vertex B is not required to be within the bounds of the mesh.
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,149 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef DETOURNAVMESHBUILDER_H
|
||||
#define DETOURNAVMESHBUILDER_H
|
||||
|
||||
#include "DetourAlloc.h"
|
||||
|
||||
/// Represents the source data used to build an navigation mesh tile.
|
||||
/// @ingroup detour
|
||||
struct dtNavMeshCreateParams
|
||||
{
|
||||
|
||||
/// @name Polygon Mesh Attributes
|
||||
/// Used to create the base navigation graph.
|
||||
/// See #rcPolyMesh for details related to these attributes.
|
||||
/// @{
|
||||
|
||||
const unsigned short* verts; ///< The polygon mesh vertices. [(x, y, z) * #vertCount] [Unit: vx]
|
||||
int vertCount; ///< The number vertices in the polygon mesh. [Limit: >= 3]
|
||||
const unsigned short* polys; ///< The polygon data. [Size: #polyCount * 2 * #nvp]
|
||||
const unsigned short* polyFlags; ///< The user defined flags assigned to each polygon. [Size: #polyCount]
|
||||
const unsigned char* polyAreas; ///< The user defined area ids assigned to each polygon. [Size: #polyCount]
|
||||
int polyCount; ///< Number of polygons in the mesh. [Limit: >= 1]
|
||||
int nvp; ///< Number maximum number of vertices per polygon. [Limit: >= 3]
|
||||
|
||||
/// @}
|
||||
/// @name Height Detail Attributes (Optional)
|
||||
/// See #rcPolyMeshDetail for details related to these attributes.
|
||||
/// @{
|
||||
|
||||
const unsigned int* detailMeshes; ///< The height detail sub-mesh data. [Size: 4 * #polyCount]
|
||||
const float* detailVerts; ///< The detail mesh vertices. [Size: 3 * #detailVertsCount] [Unit: wu]
|
||||
int detailVertsCount; ///< The number of vertices in the detail mesh.
|
||||
const unsigned char* detailTris; ///< The detail mesh triangles. [Size: 4 * #detailTriCount]
|
||||
int detailTriCount; ///< The number of triangles in the detail mesh.
|
||||
|
||||
/// @}
|
||||
/// @name Off-Mesh Connections Attributes (Optional)
|
||||
/// Used to define a custom point-to-point edge within the navigation graph, an
|
||||
/// off-mesh connection is a user defined traversable connection made up to two vertices,
|
||||
/// at least one of which resides within a navigation mesh polygon.
|
||||
/// @{
|
||||
|
||||
/// Off-mesh connection vertices. [(ax, ay, az, bx, by, bz) * #offMeshConCount] [Unit: wu]
|
||||
const float* offMeshConVerts;
|
||||
/// Off-mesh connection radii. [Size: #offMeshConCount] [Unit: wu]
|
||||
const float* offMeshConRad;
|
||||
/// User defined flags assigned to the off-mesh connections. [Size: #offMeshConCount]
|
||||
const unsigned short* offMeshConFlags;
|
||||
/// User defined area ids assigned to the off-mesh connections. [Size: #offMeshConCount]
|
||||
const unsigned char* offMeshConAreas;
|
||||
/// The permitted travel direction of the off-mesh connections. [Size: #offMeshConCount]
|
||||
///
|
||||
/// 0 = Travel only from endpoint A to endpoint B.<br/>
|
||||
/// #DT_OFFMESH_CON_BIDIR = Bidirectional travel.
|
||||
const unsigned char* offMeshConDir;
|
||||
/// The user defined ids of the off-mesh connection. [Size: #offMeshConCount]
|
||||
const unsigned int* offMeshConUserID;
|
||||
/// The number of off-mesh connections. [Limit: >= 0]
|
||||
int offMeshConCount;
|
||||
|
||||
/// @}
|
||||
/// @name Tile Attributes
|
||||
/// @note The tile grid/layer data can be left at zero if the destination is a single tile mesh.
|
||||
/// @{
|
||||
|
||||
unsigned int userId; ///< The user defined id of the tile.
|
||||
int tileX; ///< The tile's x-grid location within the multi-tile destination mesh. (Along the x-axis.)
|
||||
int tileY; ///< The tile's y-grid location within the multi-tile desitation mesh. (Along the z-axis.)
|
||||
int tileLayer; ///< The tile's layer within the layered destination mesh. [Limit: >= 0] (Along the y-axis.)
|
||||
float bmin[3]; ///< The minimum bounds of the tile. [(x, y, z)] [Unit: wu]
|
||||
float bmax[3]; ///< The maximum bounds of the tile. [(x, y, z)] [Unit: wu]
|
||||
|
||||
/// @}
|
||||
/// @name General Configuration Attributes
|
||||
/// @{
|
||||
|
||||
float walkableHeight; ///< The agent height. [Unit: wu]
|
||||
float walkableRadius; ///< The agent radius. [Unit: wu]
|
||||
float walkableClimb; ///< The agent maximum traversable ledge. (Up/Down) [Unit: wu]
|
||||
float cs; ///< The xz-plane cell size of the polygon mesh. [Limit: > 0] [Unit: wu]
|
||||
float ch; ///< The y-axis cell height of the polygon mesh. [Limit: > 0] [Unit: wu]
|
||||
|
||||
/// True if a bounding volume tree should be built for the tile.
|
||||
/// @note The BVTree is not normally needed for layered navigation meshes.
|
||||
bool buildBvTree;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// Builds navigation mesh tile data from the provided tile creation data.
|
||||
/// @ingroup detour
|
||||
/// @param[in] params Tile creation data.
|
||||
/// @param[out] outData The resulting tile data.
|
||||
/// @param[out] outDataSize The size of the tile data array.
|
||||
/// @return True if the tile data was successfully created.
|
||||
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize);
|
||||
|
||||
/// Swaps the endianess of the tile data's header (#dtMeshHeader).
|
||||
/// @param[in,out] data The tile data array.
|
||||
/// @param[in] dataSize The size of the data array.
|
||||
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int dataSize);
|
||||
|
||||
/// Swaps endianess of the tile data.
|
||||
/// @param[in,out] data The tile data array.
|
||||
/// @param[in] dataSize The size of the data array.
|
||||
bool dtNavMeshDataSwapEndian(unsigned char* data, const int dataSize);
|
||||
|
||||
#endif // DETOURNAVMESHBUILDER_H
|
||||
|
||||
// This section contains detailed documentation for members that don't have
|
||||
// a source file. It reduces clutter in the main section of the header.
|
||||
|
||||
/**
|
||||
|
||||
@struct dtNavMeshCreateParams
|
||||
@par
|
||||
|
||||
This structure is used to marshal data between the Recast mesh generation pipeline and Detour navigation components.
|
||||
|
||||
See the rcPolyMesh and rcPolyMeshDetail documentation for detailed information related to mesh structure.
|
||||
|
||||
Units are usually in voxels (vx) or world units (wu). The units for voxels, grid size, and cell size
|
||||
are all based on the values of #cs and #ch.
|
||||
|
||||
The standard navigation mesh build process is to create tile data using dtCreateNavMeshData, then add the tile
|
||||
to a navigation mesh using either the dtNavMesh single tile <tt>init()</tt> function or the dtNavMesh::addTile()
|
||||
function.
|
||||
|
||||
@see dtCreateNavMeshData
|
||||
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,575 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef DETOURNAVMESHQUERY_H
|
||||
#define DETOURNAVMESHQUERY_H
|
||||
|
||||
#include "DetourNavMesh.h"
|
||||
#include "DetourStatus.h"
|
||||
|
||||
|
||||
// Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter.
|
||||
// On certain platforms indirect or virtual function call is expensive. The default
|
||||
// setting is to use non-virtual functions, the actual implementations of the functions
|
||||
// are declared as inline for maximum speed.
|
||||
|
||||
//#define DT_VIRTUAL_QUERYFILTER 1
|
||||
|
||||
/// Defines polygon filtering and traversal costs for navigation mesh query operations.
|
||||
/// @ingroup detour
|
||||
class dtQueryFilter
|
||||
{
|
||||
float m_areaCost[DT_MAX_AREAS]; ///< Cost per area type. (Used by default implementation.)
|
||||
unsigned short m_includeFlags; ///< Flags for polygons that can be visited. (Used by default implementation.)
|
||||
unsigned short m_excludeFlags; ///< Flags for polygons that should not be visted. (Used by default implementation.)
|
||||
|
||||
public:
|
||||
dtQueryFilter();
|
||||
|
||||
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||
virtual ~dtQueryFilter() { }
|
||||
#endif
|
||||
|
||||
/// Returns true if the polygon can be visited. (I.e. Is traversable.)
|
||||
/// @param[in] ref The reference id of the polygon test.
|
||||
/// @param[in] tile The tile containing the polygon.
|
||||
/// @param[in] poly The polygon to test.
|
||||
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||
virtual bool passFilter(const dtPolyRef ref,
|
||||
const dtMeshTile* tile,
|
||||
const dtPoly* poly) const;
|
||||
#else
|
||||
bool passFilter(const dtPolyRef ref,
|
||||
const dtMeshTile* tile,
|
||||
const dtPoly* poly) const;
|
||||
#endif
|
||||
|
||||
/// Returns cost to move from the beginning to the end of a line segment
|
||||
/// that is fully contained within a polygon.
|
||||
/// @param[in] pa The start position on the edge of the previous and current polygon. [(x, y, z)]
|
||||
/// @param[in] pb The end position on the edge of the current and next polygon. [(x, y, z)]
|
||||
/// @param[in] prevRef The reference id of the previous polygon. [opt]
|
||||
/// @param[in] prevTile The tile containing the previous polygon. [opt]
|
||||
/// @param[in] prevPoly The previous polygon. [opt]
|
||||
/// @param[in] curRef The reference id of the current polygon.
|
||||
/// @param[in] curTile The tile containing the current polygon.
|
||||
/// @param[in] curPoly The current polygon.
|
||||
/// @param[in] nextRef The refernece id of the next polygon. [opt]
|
||||
/// @param[in] nextTile The tile containing the next polygon. [opt]
|
||||
/// @param[in] nextPoly The next polygon. [opt]
|
||||
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||
virtual float getCost(const float* pa, const float* pb,
|
||||
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
||||
const dtPolyRef curRef, const dtMeshTile* curTile, const dtPoly* curPoly,
|
||||
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
||||
#else
|
||||
float getCost(const float* pa, const float* pb,
|
||||
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
||||
const dtPolyRef curRef, const dtMeshTile* curTile, const dtPoly* curPoly,
|
||||
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
||||
#endif
|
||||
|
||||
/// @name Getters and setters for the default implementation data.
|
||||
///@{
|
||||
|
||||
/// Returns the traversal cost of the area.
|
||||
/// @param[in] i The id of the area.
|
||||
/// @returns The traversal cost of the area.
|
||||
inline float getAreaCost(const int i) const { return m_areaCost[i]; }
|
||||
|
||||
/// Sets the traversal cost of the area.
|
||||
/// @param[in] i The id of the area.
|
||||
/// @param[in] cost The new cost of traversing the area.
|
||||
inline void setAreaCost(const int i, const float cost) { m_areaCost[i] = cost; }
|
||||
|
||||
/// Returns the include flags for the filter.
|
||||
/// Any polygons that include one or more of these flags will be
|
||||
/// included in the operation.
|
||||
inline unsigned short getIncludeFlags() const { return m_includeFlags; }
|
||||
|
||||
/// Sets the include flags for the filter.
|
||||
/// @param[in] flags The new flags.
|
||||
inline void setIncludeFlags(const unsigned short flags) { m_includeFlags = flags; }
|
||||
|
||||
/// Returns the exclude flags for the filter.
|
||||
/// Any polygons that include one ore more of these flags will be
|
||||
/// excluded from the operation.
|
||||
inline unsigned short getExcludeFlags() const { return m_excludeFlags; }
|
||||
|
||||
/// Sets the exclude flags for the filter.
|
||||
/// @param[in] flags The new flags.
|
||||
inline void setExcludeFlags(const unsigned short flags) { m_excludeFlags = flags; }
|
||||
|
||||
///@}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Provides information about raycast hit
|
||||
/// filled by dtNavMeshQuery::raycast
|
||||
/// @ingroup detour
|
||||
struct dtRaycastHit
|
||||
{
|
||||
/// The hit parameter. (FLT_MAX if no wall hit.)
|
||||
float t;
|
||||
|
||||
/// hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
||||
float hitNormal[3];
|
||||
|
||||
/// The index of the edge on the final polygon where the wall was hit.
|
||||
int hitEdgeIndex;
|
||||
|
||||
/// Pointer to an array of reference ids of the visited polygons. [opt]
|
||||
dtPolyRef* path;
|
||||
|
||||
/// The number of visited polygons. [opt]
|
||||
int pathCount;
|
||||
|
||||
/// The maximum number of polygons the @p path array can hold.
|
||||
int maxPath;
|
||||
|
||||
/// The cost of the path until hit.
|
||||
float pathCost;
|
||||
};
|
||||
|
||||
/// Provides custom polygon query behavior.
|
||||
/// Used by dtNavMeshQuery::queryPolygons.
|
||||
/// @ingroup detour
|
||||
class dtPolyQuery
|
||||
{
|
||||
public:
|
||||
virtual ~dtPolyQuery() { }
|
||||
|
||||
/// Called for each batch of unique polygons touched by the search area in dtNavMeshQuery::queryPolygons.
|
||||
/// This can be called multiple times for a single query.
|
||||
virtual void process(const dtMeshTile* tile, dtPoly** polys, dtPolyRef* refs, int count) = 0;
|
||||
};
|
||||
|
||||
/// Provides the ability to perform pathfinding related queries against
|
||||
/// a navigation mesh.
|
||||
/// @ingroup detour
|
||||
class dtNavMeshQuery
|
||||
{
|
||||
public:
|
||||
dtNavMeshQuery();
|
||||
~dtNavMeshQuery();
|
||||
|
||||
/// Initializes the query object.
|
||||
/// @param[in] nav Pointer to the dtNavMesh object to use for all queries.
|
||||
/// @param[in] maxNodes Maximum number of search nodes. [Limits: 0 < value <= 65535]
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus init(const dtNavMesh* nav, const int maxNodes);
|
||||
|
||||
/// @name Standard Pathfinding Functions
|
||||
// /@{
|
||||
|
||||
/// Finds a path from the start polygon to the end polygon.
|
||||
/// @param[in] startRef The refrence id of the start polygon.
|
||||
/// @param[in] endRef The reference id of the end polygon.
|
||||
/// @param[in] startPos A position within the start polygon. [(x, y, z)]
|
||||
/// @param[in] endPos A position within the end polygon. [(x, y, z)]
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||
/// [(polyRef) * @p pathCount]
|
||||
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||
/// @param[in] maxPath The maximum number of polygons the @p path array can hold. [Limit: >= 1]
|
||||
dtStatus findPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||
const float* startPos, const float* endPos,
|
||||
const dtQueryFilter* filter,
|
||||
dtPolyRef* path, int* pathCount, const int maxPath) const;
|
||||
|
||||
/// Finds the straight path from the start to the end position within the polygon corridor.
|
||||
/// @param[in] startPos Path start position. [(x, y, z)]
|
||||
/// @param[in] endPos Path end position. [(x, y, z)]
|
||||
/// @param[in] path An array of polygon references that represent the path corridor.
|
||||
/// @param[in] pathSize The number of polygons in the @p path array.
|
||||
/// @param[out] straightPath Points describing the straight path. [(x, y, z) * @p straightPathCount].
|
||||
/// @param[out] straightPathFlags Flags describing each point. (See: #dtStraightPathFlags) [opt]
|
||||
/// @param[out] straightPathRefs The reference id of the polygon that is being entered at each point. [opt]
|
||||
/// @param[out] straightPathCount The number of points in the straight path.
|
||||
/// @param[in] maxStraightPath The maximum number of points the straight path arrays can hold. [Limit: > 0]
|
||||
/// @param[in] options Query options. (see: #dtStraightPathOptions)
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus findStraightPath(const float* startPos, const float* endPos,
|
||||
const dtPolyRef* path, const int pathSize,
|
||||
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||
int* straightPathCount, const int maxStraightPath, const int options = 0) const;
|
||||
|
||||
///@}
|
||||
/// @name Sliced Pathfinding Functions
|
||||
/// Common use case:
|
||||
/// -# Call initSlicedFindPath() to initialize the sliced path query.
|
||||
/// -# Call updateSlicedFindPath() until it returns complete.
|
||||
/// -# Call finalizeSlicedFindPath() to get the path.
|
||||
///@{
|
||||
|
||||
/// Intializes a sliced path query.
|
||||
/// @param[in] startRef The refrence id of the start polygon.
|
||||
/// @param[in] endRef The reference id of the end polygon.
|
||||
/// @param[in] startPos A position within the start polygon. [(x, y, z)]
|
||||
/// @param[in] endPos A position within the end polygon. [(x, y, z)]
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[in] options query options (see: #dtFindPathOptions)
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||
const float* startPos, const float* endPos,
|
||||
const dtQueryFilter* filter, const unsigned int options = 0);
|
||||
|
||||
/// Updates an in-progress sliced path query.
|
||||
/// @param[in] maxIter The maximum number of iterations to perform.
|
||||
/// @param[out] doneIters The actual number of iterations completed. [opt]
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus updateSlicedFindPath(const int maxIter, int* doneIters);
|
||||
|
||||
/// Finalizes and returns the results of a sliced path query.
|
||||
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||
/// [(polyRef) * @p pathCount]
|
||||
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||
/// @param[in] maxPath The max number of polygons the path array can hold. [Limit: >= 1]
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath);
|
||||
|
||||
/// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest
|
||||
/// polygon on the existing path that was visited during the search.
|
||||
/// @param[in] existing An array of polygon references for the existing path.
|
||||
/// @param[in] existingSize The number of polygon in the @p existing array.
|
||||
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||
/// [(polyRef) * @p pathCount]
|
||||
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||
/// @param[in] maxPath The max number of polygons the @p path array can hold. [Limit: >= 1]
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
|
||||
dtPolyRef* path, int* pathCount, const int maxPath);
|
||||
|
||||
///@}
|
||||
/// @name Dijkstra Search Functions
|
||||
/// @{
|
||||
|
||||
/// Finds the polygons along the navigation graph that touch the specified circle.
|
||||
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||
/// @param[in] radius The radius of the search circle.
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[out] resultRef The reference ids of the polygons touched by the circle. [opt]
|
||||
/// @param[out] resultParent The reference ids of the parent polygons for each result.
|
||||
/// Zero if a result polygon has no parent. [opt]
|
||||
/// @param[out] resultCost The search cost from @p centerPos to the polygon. [opt]
|
||||
/// @param[out] resultCount The number of polygons found. [opt]
|
||||
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius,
|
||||
const dtQueryFilter* filter,
|
||||
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
||||
int* resultCount, const int maxResult) const;
|
||||
|
||||
/// Finds the polygons along the naviation graph that touch the specified convex polygon.
|
||||
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||
/// @param[in] verts The vertices describing the convex polygon. (CCW)
|
||||
/// [(x, y, z) * @p nverts]
|
||||
/// @param[in] nverts The number of vertices in the polygon.
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[out] resultRef The reference ids of the polygons touched by the search polygon. [opt]
|
||||
/// @param[out] resultParent The reference ids of the parent polygons for each result. Zero if a
|
||||
/// result polygon has no parent. [opt]
|
||||
/// @param[out] resultCost The search cost from the centroid point to the polygon. [opt]
|
||||
/// @param[out] resultCount The number of polygons found.
|
||||
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus findPolysAroundShape(dtPolyRef startRef, const float* verts, const int nverts,
|
||||
const dtQueryFilter* filter,
|
||||
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
||||
int* resultCount, const int maxResult) const;
|
||||
|
||||
/// Gets a path from the explored nodes in the previous search.
|
||||
/// @param[in] endRef The reference id of the end polygon.
|
||||
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||
/// [(polyRef) * @p pathCount]
|
||||
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||
/// @param[in] maxPath The maximum number of polygons the @p path array can hold. [Limit: >= 0]
|
||||
/// @returns The status flags. Returns DT_FAILURE | DT_INVALID_PARAM if any parameter is wrong, or if
|
||||
/// @p endRef was not explored in the previous search. Returns DT_SUCCESS | DT_BUFFER_TOO_SMALL
|
||||
/// if @p path cannot contain the entire path. In this case it is filled to capacity with a partial path.
|
||||
/// Otherwise returns DT_SUCCESS.
|
||||
/// @remarks The result of this function depends on the state of the query object. For that reason it should only
|
||||
/// be used immediately after one of the two Dijkstra searches, findPolysAroundCircle or findPolysAroundShape.
|
||||
dtStatus getPathFromDijkstraSearch(dtPolyRef endRef, dtPolyRef* path, int* pathCount, int maxPath) const;
|
||||
|
||||
/// @}
|
||||
/// @name Local Query Functions
|
||||
///@{
|
||||
|
||||
/// Finds the polygon nearest to the specified center point.
|
||||
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||
/// @param[in] extents The search distance along each axis. [(x, y, z)]
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[out] nearestRef The reference id of the nearest polygon.
|
||||
/// @param[out] nearestPt The nearest point on the polygon. [opt] [(x, y, z)]
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus findNearestPoly(const float* center, const float* extents,
|
||||
const dtQueryFilter* filter,
|
||||
dtPolyRef* nearestRef, float* nearestPt) const;
|
||||
|
||||
/// Finds polygons that overlap the search box.
|
||||
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||
/// @param[in] extents The search distance along each axis. [(x, y, z)]
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[out] polys The reference ids of the polygons that overlap the query box.
|
||||
/// @param[out] polyCount The number of polygons in the search result.
|
||||
/// @param[in] maxPolys The maximum number of polygons the search result can hold.
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus queryPolygons(const float* center, const float* extents,
|
||||
const dtQueryFilter* filter,
|
||||
dtPolyRef* polys, int* polyCount, const int maxPolys) const;
|
||||
|
||||
/// Finds polygons that overlap the search box.
|
||||
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||
/// @param[in] extents The search distance along each axis. [(x, y, z)]
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[in] query The query. Polygons found will be batched together and passed to this query.
|
||||
dtStatus queryPolygons(const float* center, const float* extents,
|
||||
const dtQueryFilter* filter, dtPolyQuery* query) const;
|
||||
|
||||
/// Finds the non-overlapping navigation polygons in the local neighbourhood around the center position.
|
||||
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||
/// @param[in] centerPos The center of the query circle. [(x, y, z)]
|
||||
/// @param[in] radius The radius of the query circle.
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[out] resultRef The reference ids of the polygons touched by the circle.
|
||||
/// @param[out] resultParent The reference ids of the parent polygons for each result.
|
||||
/// Zero if a result polygon has no parent. [opt]
|
||||
/// @param[out] resultCount The number of polygons found.
|
||||
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus findLocalNeighbourhood(dtPolyRef startRef, const float* centerPos, const float radius,
|
||||
const dtQueryFilter* filter,
|
||||
dtPolyRef* resultRef, dtPolyRef* resultParent,
|
||||
int* resultCount, const int maxResult) const;
|
||||
|
||||
/// Moves from the start to the end position constrained to the navigation mesh.
|
||||
/// @param[in] startRef The reference id of the start polygon.
|
||||
/// @param[in] startPos A position of the mover within the start polygon. [(x, y, x)]
|
||||
/// @param[in] endPos The desired end position of the mover. [(x, y, z)]
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[out] resultPos The result position of the mover. [(x, y, z)]
|
||||
/// @param[out] visited The reference ids of the polygons visited during the move.
|
||||
/// @param[out] visitedCount The number of polygons visited during the move.
|
||||
/// @param[in] maxVisitedSize The maximum number of polygons the @p visited array can hold.
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||
const dtQueryFilter* filter,
|
||||
float* resultPos, dtPolyRef* visited, int* visitedCount, const int maxVisitedSize) const;
|
||||
|
||||
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
||||
/// the start position toward the end position.
|
||||
/// @note A wrapper around raycast(..., RaycastHit*). Retained for backward compatibility.
|
||||
/// @param[in] startRef The reference id of the start polygon.
|
||||
/// @param[in] startPos A position within the start polygon representing
|
||||
/// the start of the ray. [(x, y, z)]
|
||||
/// @param[in] endPos The position to cast the ray toward. [(x, y, z)]
|
||||
/// @param[out] t The hit parameter. (FLT_MAX if no wall hit.)
|
||||
/// @param[out] hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[out] path The reference ids of the visited polygons. [opt]
|
||||
/// @param[out] pathCount The number of visited polygons. [opt]
|
||||
/// @param[in] maxPath The maximum number of polygons the @p path array can hold.
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||
const dtQueryFilter* filter,
|
||||
float* t, float* hitNormal, dtPolyRef* path, int* pathCount, const int maxPath) const;
|
||||
|
||||
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
||||
/// the start position toward the end position.
|
||||
/// @param[in] startRef The reference id of the start polygon.
|
||||
/// @param[in] startPos A position within the start polygon representing
|
||||
/// the start of the ray. [(x, y, z)]
|
||||
/// @param[in] endPos The position to cast the ray toward. [(x, y, z)]
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[in] flags govern how the raycast behaves. See dtRaycastOptions
|
||||
/// @param[out] hit Pointer to a raycast hit structure which will be filled by the results.
|
||||
/// @param[in] prevRef parent of start ref. Used during for cost calculation [opt]
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||
const dtQueryFilter* filter, const unsigned int options,
|
||||
dtRaycastHit* hit, dtPolyRef prevRef = 0) const;
|
||||
|
||||
|
||||
/// Finds the distance from the specified position to the nearest polygon wall.
|
||||
/// @param[in] startRef The reference id of the polygon containing @p centerPos.
|
||||
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||
/// @param[in] maxRadius The radius of the search circle.
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[out] hitDist The distance to the nearest wall from @p centerPos.
|
||||
/// @param[out] hitPos The nearest position on the wall that was hit. [(x, y, z)]
|
||||
/// @param[out] hitNormal The normalized ray formed from the wall point to the
|
||||
/// source point. [(x, y, z)]
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus findDistanceToWall(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
||||
const dtQueryFilter* filter,
|
||||
float* hitDist, float* hitPos, float* hitNormal) const;
|
||||
|
||||
/// Returns the segments for the specified polygon, optionally including portals.
|
||||
/// @param[in] ref The reference id of the polygon.
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[out] segmentVerts The segments. [(ax, ay, az, bx, by, bz) * segmentCount]
|
||||
/// @param[out] segmentRefs The reference ids of each segment's neighbor polygon.
|
||||
/// Or zero if the segment is a wall. [opt] [(parentRef) * @p segmentCount]
|
||||
/// @param[out] segmentCount The number of segments returned.
|
||||
/// @param[in] maxSegments The maximum number of segments the result arrays can hold.
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter,
|
||||
float* segmentVerts, dtPolyRef* segmentRefs, int* segmentCount,
|
||||
const int maxSegments) const;
|
||||
|
||||
/// Returns random location on navmesh.
|
||||
/// Polygons are chosen weighted by area. The search runs in linear related to number of polygon.
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[in] frand Function returning a random number [0..1).
|
||||
/// @param[out] randomRef The reference id of the random location.
|
||||
/// @param[out] randomPt The random location.
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus findRandomPoint(const dtQueryFilter* filter, float (*frand)(),
|
||||
dtPolyRef* randomRef, float* randomPt) const;
|
||||
|
||||
/// Returns random location on navmesh within the reach of specified location.
|
||||
/// Polygons are chosen weighted by area. The search runs in linear related to number of polygon.
|
||||
/// The location is not exactly constrained by the circle, but it limits the visited polygons.
|
||||
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||
/// @param[in] filter The polygon filter to apply to the query.
|
||||
/// @param[in] frand Function returning a random number [0..1).
|
||||
/// @param[out] randomRef The reference id of the random location.
|
||||
/// @param[out] randomPt The random location. [(x, y, z)]
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus findRandomPointAroundCircle(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
||||
const dtQueryFilter* filter, float (*frand)(),
|
||||
dtPolyRef* randomRef, float* randomPt) const;
|
||||
|
||||
/// Finds the closest point on the specified polygon.
|
||||
/// @param[in] ref The reference id of the polygon.
|
||||
/// @param[in] pos The position to check. [(x, y, z)]
|
||||
/// @param[out] closest The closest point on the polygon. [(x, y, z)]
|
||||
/// @param[out] posOverPoly True of the position is over the polygon.
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
|
||||
|
||||
/// Returns a point on the boundary closest to the source point if the source point is outside the
|
||||
/// polygon's xz-bounds.
|
||||
/// @param[in] ref The reference id to the polygon.
|
||||
/// @param[in] pos The position to check. [(x, y, z)]
|
||||
/// @param[out] closest The closest point. [(x, y, z)]
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const;
|
||||
|
||||
/// Gets the height of the polygon at the provided position using the height detail. (Most accurate.)
|
||||
/// @param[in] ref The reference id of the polygon.
|
||||
/// @param[in] pos A position within the xz-bounds of the polygon. [(x, y, z)]
|
||||
/// @param[out] height The height at the surface of the polygon.
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus getPolyHeight(dtPolyRef ref, const float* pos, float* height) const;
|
||||
|
||||
/// @}
|
||||
/// @name Miscellaneous Functions
|
||||
/// @{
|
||||
|
||||
/// Returns true if the polygon reference is valid and passes the filter restrictions.
|
||||
/// @param[in] ref The polygon reference to check.
|
||||
/// @param[in] filter The filter to apply.
|
||||
bool isValidPolyRef(dtPolyRef ref, const dtQueryFilter* filter) const;
|
||||
|
||||
/// Returns true if the polygon reference is in the closed list.
|
||||
/// @param[in] ref The reference id of the polygon to check.
|
||||
/// @returns True if the polygon is in closed list.
|
||||
bool isInClosedList(dtPolyRef ref) const;
|
||||
|
||||
/// Gets the node pool.
|
||||
/// @returns The node pool.
|
||||
class dtNodePool* getNodePool() const { return m_nodePool; }
|
||||
|
||||
/// Gets the navigation mesh the query object is using.
|
||||
/// @return The navigation mesh the query object is using.
|
||||
const dtNavMesh* getAttachedNavMesh() const { return m_nav; }
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator
|
||||
dtNavMeshQuery(const dtNavMeshQuery&);
|
||||
dtNavMeshQuery& operator=(const dtNavMeshQuery&);
|
||||
|
||||
/// Queries polygons within a tile.
|
||||
void queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
||||
const dtQueryFilter* filter, dtPolyQuery* query) const;
|
||||
|
||||
/// Returns portal points between two polygons.
|
||||
dtStatus getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right,
|
||||
unsigned char& fromType, unsigned char& toType) const;
|
||||
dtStatus getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
||||
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
||||
float* left, float* right) const;
|
||||
|
||||
/// Returns edge mid point between two polygons.
|
||||
dtStatus getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const;
|
||||
dtStatus getEdgeMidPoint(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
||||
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
||||
float* mid) const;
|
||||
|
||||
// Appends vertex to a straight path
|
||||
dtStatus appendVertex(const float* pos, const unsigned char flags, const dtPolyRef ref,
|
||||
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||
int* straightPathCount, const int maxStraightPath) const;
|
||||
|
||||
// Appends intermediate portal points to a straight path.
|
||||
dtStatus appendPortals(const int startIdx, const int endIdx, const float* endPos, const dtPolyRef* path,
|
||||
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||
int* straightPathCount, const int maxStraightPath, const int options) const;
|
||||
|
||||
// Gets the path leading to the specified end node.
|
||||
dtStatus getPathToNode(struct dtNode* endNode, dtPolyRef* path, int* pathCount, int maxPath) const;
|
||||
|
||||
const dtNavMesh* m_nav; ///< Pointer to navmesh data.
|
||||
|
||||
struct dtQueryData
|
||||
{
|
||||
dtStatus status;
|
||||
struct dtNode* lastBestNode;
|
||||
float lastBestNodeCost;
|
||||
dtPolyRef startRef, endRef;
|
||||
float startPos[3], endPos[3];
|
||||
const dtQueryFilter* filter;
|
||||
unsigned int options;
|
||||
float raycastLimitSqr;
|
||||
};
|
||||
dtQueryData m_query; ///< Sliced query state.
|
||||
|
||||
class dtNodePool* m_tinyNodePool; ///< Pointer to small node pool.
|
||||
class dtNodePool* m_nodePool; ///< Pointer to node pool.
|
||||
class dtNodeQueue* m_openList; ///< Pointer to open list queue.
|
||||
};
|
||||
|
||||
/// Allocates a query object using the Detour allocator.
|
||||
/// @return An allocated query object, or null on failure.
|
||||
/// @ingroup detour
|
||||
dtNavMeshQuery* dtAllocNavMeshQuery();
|
||||
|
||||
/// Frees the specified query object using the Detour allocator.
|
||||
/// @param[in] query A query object allocated using #dtAllocNavMeshQuery
|
||||
/// @ingroup detour
|
||||
void dtFreeNavMeshQuery(dtNavMeshQuery* query);
|
||||
|
||||
#endif // DETOURNAVMESHQUERY_H
|
||||
@@ -0,0 +1,168 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef DETOURNODE_H
|
||||
#define DETOURNODE_H
|
||||
|
||||
#include "DetourNavMesh.h"
|
||||
|
||||
enum dtNodeFlags
|
||||
{
|
||||
DT_NODE_OPEN = 0x01,
|
||||
DT_NODE_CLOSED = 0x02,
|
||||
DT_NODE_PARENT_DETACHED = 0x04, // parent of the node is not adjacent. Found using raycast.
|
||||
};
|
||||
|
||||
typedef unsigned short dtNodeIndex;
|
||||
static const dtNodeIndex DT_NULL_IDX = (dtNodeIndex)~0;
|
||||
|
||||
static const int DT_NODE_PARENT_BITS = 24;
|
||||
static const int DT_NODE_STATE_BITS = 2;
|
||||
struct dtNode
|
||||
{
|
||||
float pos[3]; ///< Position of the node.
|
||||
float cost; ///< Cost from previous node to current node.
|
||||
float total; ///< Cost up to the node.
|
||||
unsigned int pidx : DT_NODE_PARENT_BITS; ///< Index to parent node.
|
||||
unsigned int state : DT_NODE_STATE_BITS; ///< extra state information. A polyRef can have multiple nodes with different extra info. see DT_MAX_STATES_PER_NODE
|
||||
unsigned int flags : 3; ///< Node flags. A combination of dtNodeFlags.
|
||||
dtPolyRef id; ///< Polygon ref the node corresponds to.
|
||||
};
|
||||
|
||||
static const int DT_MAX_STATES_PER_NODE = 1 << DT_NODE_STATE_BITS; // number of extra states per node. See dtNode::state
|
||||
|
||||
class dtNodePool
|
||||
{
|
||||
public:
|
||||
dtNodePool(int maxNodes, int hashSize);
|
||||
~dtNodePool();
|
||||
void clear();
|
||||
|
||||
// Get a dtNode by ref and extra state information. If there is none then - allocate
|
||||
// There can be more than one node for the same polyRef but with different extra state information
|
||||
dtNode* getNode(dtPolyRef id, unsigned char state=0);
|
||||
dtNode* findNode(dtPolyRef id, unsigned char state);
|
||||
unsigned int findNodes(dtPolyRef id, dtNode** nodes, const int maxNodes);
|
||||
|
||||
inline unsigned int getNodeIdx(const dtNode* node) const
|
||||
{
|
||||
if (!node) return 0;
|
||||
return (unsigned int)(node - m_nodes) + 1;
|
||||
}
|
||||
|
||||
inline dtNode* getNodeAtIdx(unsigned int idx)
|
||||
{
|
||||
if (!idx) return 0;
|
||||
return &m_nodes[idx - 1];
|
||||
}
|
||||
|
||||
inline const dtNode* getNodeAtIdx(unsigned int idx) const
|
||||
{
|
||||
if (!idx) return 0;
|
||||
return &m_nodes[idx - 1];
|
||||
}
|
||||
|
||||
inline int getMemUsed() const
|
||||
{
|
||||
return sizeof(*this) +
|
||||
sizeof(dtNode)*m_maxNodes +
|
||||
sizeof(dtNodeIndex)*m_maxNodes +
|
||||
sizeof(dtNodeIndex)*m_hashSize;
|
||||
}
|
||||
|
||||
inline int getMaxNodes() const { return m_maxNodes; }
|
||||
|
||||
inline int getHashSize() const { return m_hashSize; }
|
||||
inline dtNodeIndex getFirst(int bucket) const { return m_first[bucket]; }
|
||||
inline dtNodeIndex getNext(int i) const { return m_next[i]; }
|
||||
inline int getNodeCount() const { return m_nodeCount; }
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
dtNodePool(const dtNodePool&);
|
||||
dtNodePool& operator=(const dtNodePool&);
|
||||
|
||||
dtNode* m_nodes;
|
||||
dtNodeIndex* m_first;
|
||||
dtNodeIndex* m_next;
|
||||
const int m_maxNodes;
|
||||
const int m_hashSize;
|
||||
int m_nodeCount;
|
||||
};
|
||||
|
||||
class dtNodeQueue
|
||||
{
|
||||
public:
|
||||
dtNodeQueue(int n);
|
||||
~dtNodeQueue();
|
||||
|
||||
inline void clear() { m_size = 0; }
|
||||
|
||||
inline dtNode* top() { return m_heap[0]; }
|
||||
|
||||
inline dtNode* pop()
|
||||
{
|
||||
dtNode* result = m_heap[0];
|
||||
m_size--;
|
||||
trickleDown(0, m_heap[m_size]);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void push(dtNode* node)
|
||||
{
|
||||
m_size++;
|
||||
bubbleUp(m_size-1, node);
|
||||
}
|
||||
|
||||
inline void modify(dtNode* node)
|
||||
{
|
||||
for (int i = 0; i < m_size; ++i)
|
||||
{
|
||||
if (m_heap[i] == node)
|
||||
{
|
||||
bubbleUp(i, node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool empty() const { return m_size == 0; }
|
||||
|
||||
inline int getMemUsed() const
|
||||
{
|
||||
return sizeof(*this) +
|
||||
sizeof(dtNode*) * (m_capacity + 1);
|
||||
}
|
||||
|
||||
inline int getCapacity() const { return m_capacity; }
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
dtNodeQueue(const dtNodeQueue&);
|
||||
dtNodeQueue& operator=(const dtNodeQueue&);
|
||||
|
||||
void bubbleUp(int i, dtNode* node);
|
||||
void trickleDown(int i, dtNode* node);
|
||||
|
||||
dtNode** m_heap;
|
||||
const int m_capacity;
|
||||
int m_size;
|
||||
};
|
||||
|
||||
|
||||
#endif // DETOURNODE_H
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef DETOURSTATUS_H
|
||||
#define DETOURSTATUS_H
|
||||
|
||||
typedef unsigned int dtStatus;
|
||||
|
||||
// High level status.
|
||||
static const unsigned int DT_FAILURE = 1u << 31; // Operation failed.
|
||||
static const unsigned int DT_SUCCESS = 1u << 30; // Operation succeed.
|
||||
static const unsigned int DT_IN_PROGRESS = 1u << 29; // Operation still in progress.
|
||||
|
||||
// Detail information for status.
|
||||
static const unsigned int DT_STATUS_DETAIL_MASK = 0x0ffffff;
|
||||
static const unsigned int DT_WRONG_MAGIC = 1 << 0; // Input data is not recognized.
|
||||
static const unsigned int DT_WRONG_VERSION = 1 << 1; // Input data is in wrong version.
|
||||
static const unsigned int DT_OUT_OF_MEMORY = 1 << 2; // Operation ran out of memory.
|
||||
static const unsigned int DT_INVALID_PARAM = 1 << 3; // An input parameter was invalid.
|
||||
static const unsigned int DT_BUFFER_TOO_SMALL = 1 << 4; // Result buffer for the query was too small to store all results.
|
||||
static const unsigned int DT_OUT_OF_NODES = 1 << 5; // Query ran out of nodes during search.
|
||||
static const unsigned int DT_PARTIAL_RESULT = 1 << 6; // Query did not reach the end location, returning best guess.
|
||||
|
||||
|
||||
// Returns true of status is success.
|
||||
inline bool dtStatusSucceed(dtStatus status)
|
||||
{
|
||||
return (status & DT_SUCCESS) != 0;
|
||||
}
|
||||
|
||||
// Returns true of status is failure.
|
||||
inline bool dtStatusFailed(dtStatus status)
|
||||
{
|
||||
return (status & DT_FAILURE) != 0;
|
||||
}
|
||||
|
||||
// Returns true of status is in progress.
|
||||
inline bool dtStatusInProgress(dtStatus status)
|
||||
{
|
||||
return (status & DT_IN_PROGRESS) != 0;
|
||||
}
|
||||
|
||||
// Returns true if specific detail is set.
|
||||
inline bool dtStatusDetail(dtStatus status, unsigned int detail)
|
||||
{
|
||||
return (status & detail) != 0;
|
||||
}
|
||||
|
||||
#endif // DETOURSTATUS_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user