mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
EQStream abstraction layer
This commit is contained in:
parent
751e61d6e5
commit
5cad3f62d0
@ -323,7 +323,8 @@ IF(EQEMU_BUILD_LUA)
|
||||
SET(BOOST_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/boost")
|
||||
|
||||
FIND_PACKAGE(Boost REQUIRED)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${LUA_INCLUDE_DIR}" "${Boost_INCLUDE_DIRS}" "luabind")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${LUA_INCLUDE_DIR}" "${Boost_INCLUDE_DIRS}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/luabind")
|
||||
|
||||
OPTION(EQEMU_SANITIZE_LUA_LIBS "Sanitize Lua Libraries (Remove OS and IO standard libraries from being able to run)." ON)
|
||||
IF(EQEMU_SANITIZE_LUA_LIBS)
|
||||
@ -331,14 +332,18 @@ IF(EQEMU_BUILD_LUA)
|
||||
ENDIF(EQEMU_SANITIZE_LUA_LIBS)
|
||||
ENDIF(EQEMU_BUILD_LUA)
|
||||
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}" "${MySQL_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/common/glm")
|
||||
|
||||
IF(EQEMU_BUILD_LUA)
|
||||
ADD_SUBDIRECTORY(luabind)
|
||||
ENDIF(EQEMU_BUILD_LUA)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${MySQL_INCLUDE_DIR}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/common/glm")
|
||||
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")
|
||||
|
||||
IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
|
||||
ADD_SUBDIRECTORY(common)
|
||||
ADD_SUBDIRECTORY(libs)
|
||||
ENDIF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
|
||||
IF(EQEMU_BUILD_SERVER)
|
||||
ADD_SUBDIRECTORY(shared_memory)
|
||||
|
||||
@ -9,7 +9,7 @@ SET(export_headers
|
||||
|
||||
ADD_EXECUTABLE(export_client_files ${export_sources} ${export_headers})
|
||||
|
||||
INSTALL(TARGETS export_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
INSTALL(TARGETS export_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(export_client_files common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY})
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ SET(import_headers
|
||||
|
||||
ADD_EXECUTABLE(import_client_files ${import_sources} ${import_headers})
|
||||
|
||||
INSTALL(TARGETS import_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
INSTALL(TARGETS import_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(import_client_files common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY})
|
||||
|
||||
|
||||
@ -75,6 +75,10 @@ SET(common_sources
|
||||
worldconn.cpp
|
||||
xml_parser.cpp
|
||||
platform.cpp
|
||||
net/crc32.cpp
|
||||
net/daybreak_connection.cpp
|
||||
net/eqstream.cpp
|
||||
net/packet.cpp
|
||||
patches/patches.cpp
|
||||
patches/sod.cpp
|
||||
patches/sod_limits.cpp
|
||||
@ -210,6 +214,15 @@ SET(common_headers
|
||||
worldconn.h
|
||||
xml_parser.h
|
||||
zone_numbers.h
|
||||
event/background_task.h
|
||||
event/event_loop.h
|
||||
event/timer.h
|
||||
net/crc32.h
|
||||
net/daybreak_connection.h
|
||||
net/daybreak_structs.h
|
||||
net/endian.h
|
||||
net/eqstream.h
|
||||
net/packet.h
|
||||
patches/patches.h
|
||||
patches/sod.h
|
||||
# patches/sod_itemfields.h
|
||||
@ -261,6 +274,26 @@ SET(common_headers
|
||||
StackWalker/StackWalker.h
|
||||
tinyxml/tinystr.h
|
||||
tinyxml/tinyxml.h
|
||||
util/memory_stream.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Event FILES
|
||||
event/background_task.h
|
||||
event/event_loop.h
|
||||
event/timer.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Net FILES
|
||||
net/crc32.cpp
|
||||
net/crc32.h
|
||||
net/daybreak_connection.cpp
|
||||
net/daybreak_connection.h
|
||||
net/daybreak_structs.h
|
||||
net/endian.h
|
||||
net/eqstream.h
|
||||
net/eqstream.cpp
|
||||
net/packet.cpp
|
||||
net/packet.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Patches FILES
|
||||
@ -355,6 +388,10 @@ SOURCE_GROUP(TinyXML FILES
|
||||
tinyxml/tinyxmlparser.cpp
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Util FILES
|
||||
util/memory_stream.h
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker TinyXML)
|
||||
|
||||
ADD_LIBRARY(common ${common_sources} ${common_headers})
|
||||
|
||||
@ -115,7 +115,7 @@ public:
|
||||
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
|
||||
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
|
||||
|
||||
uint16 GetOpcodeBypass() { return opcode_bypass; }
|
||||
uint16 GetOpcodeBypass() const { return opcode_bypass; }
|
||||
void SetOpcodeBypass(uint16 v) { opcode_bypass = v; }
|
||||
|
||||
protected:
|
||||
|
||||
@ -529,7 +529,7 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req)
|
||||
if(pack->GetOpcodeBypass() != 0) {
|
||||
opcode = pack->GetOpcodeBypass();
|
||||
} else {
|
||||
opcode = (*OpMgr)->EmuToEQ(pack->emu_opcode);
|
||||
opcode = (*OpMgr)->EmuToEQ(pack->GetOpcode());
|
||||
}
|
||||
|
||||
if (!ack_req) {
|
||||
|
||||
@ -19,11 +19,11 @@
|
||||
#ifndef EQEMU_LOGSYS_H
|
||||
#define EQEMU_LOGSYS_H
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <stdio.h>
|
||||
#include <functional>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace Logs {
|
||||
@ -158,6 +158,13 @@ public:
|
||||
void SetCurrentTimeStamp(char* time_stamp); /* Used in file logs to prepend a timestamp entry for logs */
|
||||
void StartFileLogs(const std::string &log_name = ""); /* Used to declare the processes file log and to keep it open for later use */
|
||||
|
||||
template <typename... Args>
|
||||
void OutF(Logs::DebugLevel debug_level, uint16 log_category, const char *fmt, const Args&... args)
|
||||
{
|
||||
std::string log_str = fmt::format(fmt, args...);
|
||||
Out(debug_level, log_category, log_str);
|
||||
}
|
||||
|
||||
/*
|
||||
LogSettings Struct
|
||||
|
||||
|
||||
39
common/event/background_task.h
Normal file
39
common/event/background_task.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include "event_loop.h"
|
||||
|
||||
namespace EQ {
|
||||
class BackgroundTask
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(void)> BackgroundTaskFunction;
|
||||
struct BackgroundTaskBaton
|
||||
{
|
||||
BackgroundTaskFunction fn;
|
||||
BackgroundTaskFunction on_finish;
|
||||
};
|
||||
|
||||
BackgroundTask(BackgroundTaskFunction fn, BackgroundTaskFunction on_finish) {
|
||||
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;
|
||||
|
||||
m_work->data = baton;
|
||||
uv_queue_work(EventLoop::Get().Handle(), m_work, [](uv_work_t* req) {
|
||||
BackgroundTaskBaton *baton = (BackgroundTaskBaton*)req->data;
|
||||
baton->fn();
|
||||
}, [](uv_work_t* req, int status) {
|
||||
BackgroundTaskBaton *baton = (BackgroundTaskBaton*)req->data;
|
||||
baton->on_finish();
|
||||
delete baton;
|
||||
delete req;
|
||||
});
|
||||
}
|
||||
|
||||
~BackgroundTask() {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
36
common/event/event_loop.h
Normal file
36
common/event/event_loop.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <uv.h>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
class EventLoop
|
||||
{
|
||||
public:
|
||||
static EventLoop &Get() {
|
||||
static EventLoop inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
~EventLoop() {
|
||||
uv_loop_close(&m_loop);
|
||||
}
|
||||
|
||||
void Process() {
|
||||
uv_run(&m_loop, UV_RUN_NOWAIT);
|
||||
}
|
||||
|
||||
uv_loop_t* Handle() { return &m_loop; }
|
||||
|
||||
private:
|
||||
EventLoop() {
|
||||
memset(&m_loop, 0, sizeof(uv_loop_t));
|
||||
uv_loop_init(&m_loop);
|
||||
}
|
||||
|
||||
EventLoop(const EventLoop&);
|
||||
EventLoop& operator=(const EventLoop&);
|
||||
|
||||
uv_loop_t m_loop;
|
||||
};
|
||||
}
|
||||
63
common/event/timer.h
Normal file
63
common/event/timer.h
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include "event_loop.h"
|
||||
|
||||
namespace EQ {
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer(uint64_t duration_ms, bool repeats, std::function<void(void)> cb)
|
||||
{
|
||||
memset(&m_timer, 0, sizeof(uv_timer_t));
|
||||
m_cb = cb;
|
||||
m_duration_ms = duration_ms;
|
||||
m_repeats = repeats;
|
||||
m_attached = nullptr;
|
||||
Attach(EventLoop::Get().Handle());
|
||||
}
|
||||
|
||||
~Timer()
|
||||
{
|
||||
Detach();
|
||||
}
|
||||
private:
|
||||
void Execute() {
|
||||
m_cb();
|
||||
}
|
||||
|
||||
virtual void Attach(uv_loop_t *loop) {
|
||||
if (!m_attached) {
|
||||
uv_timer_init(loop, &m_timer);
|
||||
m_timer.data = this;
|
||||
|
||||
if (m_repeats) {
|
||||
uv_timer_start(&m_timer, [](uv_timer_t *handle) {
|
||||
Timer *t = (Timer*)handle->data;
|
||||
t->Execute();
|
||||
}, m_duration_ms, m_duration_ms);
|
||||
}
|
||||
else {
|
||||
uv_timer_start(&m_timer, [](uv_timer_t *handle) {
|
||||
Timer *t = (Timer*)handle->data;
|
||||
t->Execute();
|
||||
}, m_duration_ms, 0);
|
||||
}
|
||||
|
||||
m_attached = loop;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Detach() {
|
||||
if (m_attached) {
|
||||
uv_timer_stop(&m_timer);
|
||||
m_attached = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uv_timer_t m_timer;
|
||||
std::function<void(void)> m_cb;
|
||||
uint64_t m_duration_ms;
|
||||
bool m_repeats;
|
||||
uv_loop_t *m_attached;
|
||||
};
|
||||
}
|
||||
96
common/net/crc32.cpp
Normal file
96
common/net/crc32.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
#include "crc32.h"
|
||||
#include <memory.h>
|
||||
|
||||
unsigned int CRC32EncodeTable[256] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
||||
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
||||
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
||||
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
|
||||
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
|
||||
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
|
||||
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
|
||||
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
|
||||
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
|
||||
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
|
||||
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
||||
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
|
||||
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
|
||||
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
||||
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
|
||||
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
|
||||
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
|
||||
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
||||
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
|
||||
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
|
||||
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
|
||||
int EQ::Crc32(const void * data, int size)
|
||||
{
|
||||
int crc = 0xffffffff;
|
||||
auto buffer = (const uint8_t *)data;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
crc = ((crc >> 8) & 0x00FFFFFFL) ^ CRC32EncodeTable[(crc ^ *&buffer[i]) & 0x000000FFL];
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
int EQ::Crc32(const void * data, int size, int key)
|
||||
{
|
||||
int crc = 0xffffffff;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
crc = ((crc >> 8) & 0x00FFFFFFL) ^ CRC32EncodeTable[(crc ^ ((key >> (i * 8)) & 0xff)) & 0x000000FFL];
|
||||
}
|
||||
|
||||
auto buffer = (const uint8_t *)data;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
crc = ((crc >> 8) & 0x00FFFFFFL) ^ CRC32EncodeTable[(crc ^ *&buffer[i]) & 0x000000FFL];
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
9
common/net/crc32.h
Normal file
9
common/net/crc32.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
int Crc32(const void *data, int size);
|
||||
int Crc32(const void *data, int size, int key);
|
||||
}
|
||||
1262
common/net/daybreak_connection.cpp
Normal file
1262
common/net/daybreak_connection.cpp
Normal file
File diff suppressed because it is too large
Load Diff
273
common/net/daybreak_connection.h
Normal file
273
common/net/daybreak_connection.h
Normal file
@ -0,0 +1,273 @@
|
||||
#pragma once
|
||||
|
||||
#include "../random.h"
|
||||
#include "packet.h"
|
||||
#include "daybreak_structs.h"
|
||||
#include <uv.h>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
enum DaybreakProtocolOpcode
|
||||
{
|
||||
OP_Padding = 0x00,
|
||||
OP_SessionRequest = 0x01,
|
||||
OP_SessionResponse = 0x02,
|
||||
OP_Combined = 0x03,
|
||||
OP_SessionDisconnect = 0x05,
|
||||
OP_KeepAlive = 0x06,
|
||||
OP_SessionStatRequest = 0x07,
|
||||
OP_SessionStatResponse = 0x08,
|
||||
OP_Packet = 0x09,
|
||||
OP_Packet2 = 0x0a,
|
||||
OP_Packet3 = 0x0b,
|
||||
OP_Packet4 = 0x0c,
|
||||
OP_Fragment = 0x0d,
|
||||
OP_Fragment2 = 0x0e,
|
||||
OP_Fragment3 = 0x0f,
|
||||
OP_Fragment4 = 0x10,
|
||||
OP_OutOfOrderAck = 0x11,
|
||||
OP_OutOfOrderAck2 = 0x12,
|
||||
OP_OutOfOrderAck3 = 0x13,
|
||||
OP_OutOfOrderAck4 = 0x14,
|
||||
OP_Ack = 0x15,
|
||||
OP_Ack2 = 0x16,
|
||||
OP_Ack3 = 0x17,
|
||||
OP_Ack4 = 0x18,
|
||||
OP_AppCombined = 0x19,
|
||||
OP_OutboundPing = 0x1c,
|
||||
OP_OutOfSession = 0x1d
|
||||
};
|
||||
|
||||
enum DbProtocolStatus
|
||||
{
|
||||
StatusConnecting,
|
||||
StatusConnected,
|
||||
StatusDisconnecting,
|
||||
StatusDisconnected
|
||||
};
|
||||
|
||||
enum DaybreakEncodeType
|
||||
{
|
||||
EncodeNone = 0,
|
||||
EncodeCompression = 1,
|
||||
EncodeXOR = 4,
|
||||
};
|
||||
|
||||
enum SequenceOrder
|
||||
{
|
||||
SequenceCurrent,
|
||||
SequenceFuture,
|
||||
SequencePast
|
||||
};
|
||||
|
||||
typedef std::chrono::system_clock::time_point Timestamp;
|
||||
typedef std::chrono::system_clock Clock;
|
||||
|
||||
struct DaybreakConnectionStats
|
||||
{
|
||||
DaybreakConnectionStats() {
|
||||
recv_bytes = 0;
|
||||
sent_bytes = 0;
|
||||
recv_packets = 0;
|
||||
sent_packets = 0;
|
||||
total_ping = 0;
|
||||
total_acks = 0;
|
||||
min_ping = 0xFFFFFFFFFFFFFFFFUL;
|
||||
max_ping = 0;
|
||||
created = Clock::now();
|
||||
}
|
||||
|
||||
uint64_t recv_bytes;
|
||||
uint64_t sent_bytes;
|
||||
uint64_t recv_packets;
|
||||
uint64_t sent_packets;
|
||||
uint64_t total_ping;
|
||||
uint64_t total_acks;
|
||||
uint64_t min_ping;
|
||||
uint64_t max_ping;
|
||||
Timestamp created;
|
||||
};
|
||||
|
||||
class DaybreakConnectionManager;
|
||||
class DaybreakConnection;
|
||||
class DaybreakConnection
|
||||
{
|
||||
public:
|
||||
DaybreakConnection(DaybreakConnectionManager *owner, const DaybreakConnect &connect, const std::string &endpoint, int port);
|
||||
DaybreakConnection(DaybreakConnectionManager *owner, const std::string &endpoint, int port);
|
||||
~DaybreakConnection();
|
||||
|
||||
const std::string& RemoteEndpoint() const { return m_endpoint; }
|
||||
int RemotePort() const { return m_port; }
|
||||
|
||||
void Close();
|
||||
void QueuePacket(Packet &p);
|
||||
void QueuePacket(Packet &p, int stream);
|
||||
void QueuePacket(Packet &p, int stream, bool reliable);
|
||||
const DaybreakConnectionStats& GetStats() const { return m_stats; }
|
||||
void ResetStats();
|
||||
size_t GetRollingPing() const { return m_rolling_ping; }
|
||||
DbProtocolStatus GetStatus() { return m_status; }
|
||||
private:
|
||||
DaybreakConnectionManager *m_owner;
|
||||
std::string m_endpoint;
|
||||
int m_port;
|
||||
uint32_t m_connect_code;
|
||||
uint32_t m_encode_key;
|
||||
uint32_t m_max_packet_size;
|
||||
uint32_t m_crc_bytes;
|
||||
DaybreakEncodeType m_encode_passes[2];
|
||||
|
||||
Timestamp m_last_send;
|
||||
Timestamp m_last_recv;
|
||||
DbProtocolStatus m_status;
|
||||
Timestamp m_hold_time;
|
||||
std::list<WritablePacket> m_buffered_packets;
|
||||
size_t m_buffered_packets_length;
|
||||
Timestamp m_last_stats;
|
||||
DaybreakConnectionStats m_stats;
|
||||
Timestamp m_last_session_stats;
|
||||
uint64_t m_last_session_stats_ping;
|
||||
size_t m_resend_delay;
|
||||
size_t m_rolling_ping;
|
||||
|
||||
struct DaybreakSentPacket
|
||||
{
|
||||
WritablePacket packet;
|
||||
Timestamp last_sent;
|
||||
Timestamp first_sent;
|
||||
size_t times_resent;
|
||||
};
|
||||
|
||||
struct DaybreakStream
|
||||
{
|
||||
DaybreakStream() {
|
||||
sequence_in = 0;
|
||||
sequence_out = 0;
|
||||
fragment_current_bytes = 0;
|
||||
fragment_total_bytes = 0;
|
||||
}
|
||||
|
||||
uint16_t sequence_in;
|
||||
uint16_t sequence_out;
|
||||
std::map<uint16_t, Packet*> packet_queue;
|
||||
|
||||
WritablePacket fragment_packet;
|
||||
uint32_t fragment_current_bytes;
|
||||
uint32_t fragment_total_bytes;
|
||||
|
||||
std::map<uint16_t, DaybreakSentPacket> sent_packets;
|
||||
};
|
||||
|
||||
DaybreakStream m_streams[4];
|
||||
std::weak_ptr<DaybreakConnection> m_self;
|
||||
|
||||
void Process();
|
||||
void ProcessPacket(Packet &p);
|
||||
void ProcessQueue();
|
||||
void RemoveFromQueue(int stream, uint16_t seq);
|
||||
void AddToQueue(int stream, uint16_t seq, const Packet &p);
|
||||
void ProcessDecodedPacket(const Packet &p);
|
||||
void ChangeStatus(DbProtocolStatus new_status);
|
||||
bool ValidateCRC(Packet &p);
|
||||
void AppendCRC(Packet &p);
|
||||
bool PacketCanBeEncoded(Packet &p) const;
|
||||
void Decode(Packet &p, size_t offset, size_t length);
|
||||
void Encode(Packet &p, size_t offset, size_t length);
|
||||
void Decompress(Packet &p, size_t offset, size_t length);
|
||||
void Compress(Packet &p, size_t offset, size_t length);
|
||||
void ProcessResend();
|
||||
void ProcessResend(int stream);
|
||||
void Ack(int stream, uint16_t seq);
|
||||
void OutOfOrderAck(int stream, uint16_t seq);
|
||||
|
||||
void SendConnect();
|
||||
void SendKeepAlive();
|
||||
void SendAck(int stream, uint16_t seq);
|
||||
void SendOutOfOrderAck(int stream, uint16_t seq);
|
||||
void SendStatSync();
|
||||
void InternalBufferedSend(Packet &p);
|
||||
void InternalSend(Packet &p);
|
||||
void InternalQueuePacket(Packet &p, int stream_id, bool reliable);
|
||||
void FlushBuffer();
|
||||
SequenceOrder CompareSequence(uint16_t expected, uint16_t actual) const;
|
||||
|
||||
friend class DaybreakConnectionManager;
|
||||
};
|
||||
|
||||
struct DaybreakConnectionManagerOptions
|
||||
{
|
||||
DaybreakConnectionManagerOptions() {
|
||||
max_connection_count = 0;
|
||||
keepalive_delay_ms = 0;
|
||||
resend_delay_ms = 1000;
|
||||
stats_delay_ms = 10000;
|
||||
connect_delay_ms = 1000;
|
||||
stale_connection_ms = 60000;
|
||||
crc_length = 2;
|
||||
max_packet_size = 512;
|
||||
encode_passes[0] = DaybreakEncodeType::EncodeNone;
|
||||
encode_passes[1] = DaybreakEncodeType::EncodeNone;
|
||||
port = 0;
|
||||
hold_size = 384;
|
||||
hold_length_ms = 50;
|
||||
}
|
||||
|
||||
size_t max_packet_size;
|
||||
size_t max_connection_count;
|
||||
size_t keepalive_delay_ms;
|
||||
size_t resend_delay_ms;
|
||||
size_t stats_delay_ms;
|
||||
size_t connect_delay_ms;
|
||||
size_t stale_connection_ms;
|
||||
size_t crc_length;
|
||||
size_t hold_size;
|
||||
size_t hold_length_ms;
|
||||
DaybreakEncodeType encode_passes[2];
|
||||
int port;
|
||||
};
|
||||
|
||||
class DaybreakConnectionManager
|
||||
{
|
||||
public:
|
||||
DaybreakConnectionManager();
|
||||
DaybreakConnectionManager(const DaybreakConnectionManagerOptions &opts);
|
||||
~DaybreakConnectionManager();
|
||||
|
||||
void Connect(const std::string &addr, int port);
|
||||
void Process();
|
||||
void ProcessResend();
|
||||
void OnNewConnection(std::function<void(std::shared_ptr<DaybreakConnection>)> func) { m_on_new_connection = func; }
|
||||
void OnConnectionStateChange(std::function<void(std::shared_ptr<DaybreakConnection>, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; }
|
||||
void OnPacketRecv(std::function<void(std::shared_ptr<DaybreakConnection>, const Packet &)> func) { m_on_packet_recv = func; }
|
||||
private:
|
||||
void Attach(uv_loop_t *loop);
|
||||
void Detach();
|
||||
|
||||
EQEmu::Random m_rand;
|
||||
uv_timer_t m_timer;
|
||||
uv_timer_t m_resend_timer;
|
||||
uv_udp_t m_socket;
|
||||
uv_loop_t *m_attached;
|
||||
DaybreakConnectionManagerOptions m_options;
|
||||
std::function<void(std::shared_ptr<DaybreakConnection>)> m_on_new_connection;
|
||||
std::function<void(std::shared_ptr<DaybreakConnection>, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change;
|
||||
std::function<void(std::shared_ptr<DaybreakConnection>, const Packet&)> m_on_packet_recv;
|
||||
std::map<std::pair<std::string, int>, std::shared_ptr<DaybreakConnection>> m_connections;
|
||||
|
||||
void ProcessPacket(const std::string &endpoint, int port, const char *data, size_t size);
|
||||
std::shared_ptr<DaybreakConnection> FindConnectionByEndpoint(std::string addr, int port);
|
||||
void SendSessionLost(const std::string &addr, int port);
|
||||
|
||||
friend class DaybreakConnection;
|
||||
};
|
||||
}
|
||||
}
|
||||
175
common/net/daybreak_structs.h
Normal file
175
common/net/daybreak_structs.h
Normal file
@ -0,0 +1,175 @@
|
||||
#pragma once
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cstdint>
|
||||
#include "endian.h"
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
struct DaybreakHeader
|
||||
{
|
||||
static size_t size() { return 2; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakConnect
|
||||
{
|
||||
static size_t size() { return 14; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint32_t protocol_version;
|
||||
uint32_t connect_code;
|
||||
uint32_t max_packet_size;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(protocol_version),
|
||||
CEREAL_NVP(connect_code),
|
||||
CEREAL_NVP(max_packet_size));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakConnectReply
|
||||
{
|
||||
static size_t size() { return 17; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint32_t connect_code;
|
||||
uint32_t encode_key;
|
||||
uint8_t crc_bytes;
|
||||
uint8_t encode_pass1;
|
||||
uint8_t encode_pass2;
|
||||
uint32_t max_packet_size;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(connect_code),
|
||||
CEREAL_NVP(encode_key),
|
||||
CEREAL_NVP(crc_bytes),
|
||||
CEREAL_NVP(encode_pass1),
|
||||
CEREAL_NVP(encode_pass2),
|
||||
CEREAL_NVP(max_packet_size));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakDisconnect
|
||||
{
|
||||
static size_t size() { return 8; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint32_t connect_code;
|
||||
uint16_t disconnect_code;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(connect_code),
|
||||
CEREAL_NVP(disconnect_code));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakReliableHeader
|
||||
{
|
||||
static size_t size() { return 4; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint16_t sequence;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(sequence));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakReliableFragmentHeader
|
||||
{
|
||||
static size_t size() { return 4 + DaybreakReliableHeader::size(); }
|
||||
DaybreakReliableHeader reliable;
|
||||
uint32_t total_size;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(reliable),
|
||||
CEREAL_NVP(total_size));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakSessionStatRequestHeader
|
||||
{
|
||||
static size_t size() { return 40; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint16_t timestamp;
|
||||
uint32_t stat_ping;
|
||||
uint32_t avg_ping;
|
||||
uint32_t min_ping;
|
||||
uint32_t max_ping;
|
||||
uint32_t last_ping;
|
||||
uint64_t packets_sent;
|
||||
uint64_t packets_recv;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(timestamp),
|
||||
CEREAL_NVP(stat_ping),
|
||||
CEREAL_NVP(avg_ping),
|
||||
CEREAL_NVP(min_ping),
|
||||
CEREAL_NVP(max_ping),
|
||||
CEREAL_NVP(last_ping),
|
||||
CEREAL_NVP(packets_sent),
|
||||
CEREAL_NVP(packets_recv));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakSessionStatResponseHeader
|
||||
{
|
||||
static size_t size() { return 40; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint16_t timestamp;
|
||||
uint32_t our_timestamp;
|
||||
uint64_t client_sent;
|
||||
uint64_t client_recv;
|
||||
uint64_t server_sent;
|
||||
uint64_t server_recv;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(timestamp),
|
||||
CEREAL_NVP(our_timestamp),
|
||||
CEREAL_NVP(client_sent),
|
||||
CEREAL_NVP(client_recv),
|
||||
CEREAL_NVP(server_sent),
|
||||
CEREAL_NVP(server_recv));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
51
common/net/endian.h
Normal file
51
common/net/endian.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
inline bool IsLittleEndian() {
|
||||
static int32_t v = 1;
|
||||
return 1 == *(int8_t*)&v;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ByteSwap(T in) {
|
||||
static_assert(std::is_integral<T>::value, "Byte swap only works on integer types.");
|
||||
T ret;
|
||||
|
||||
char *first = (char*)∈
|
||||
char *last = (char*)&in + sizeof(in);
|
||||
char *d_first = (char*)&ret;
|
||||
while (first != last) {
|
||||
*(d_first++) = *(--last);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T HostToNetwork(T in) {
|
||||
if (IsLittleEndian()) {
|
||||
return ByteSwap(in);
|
||||
}
|
||||
else {
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T NetworkToHost(T in) {
|
||||
if (IsLittleEndian()) {
|
||||
return ByteSwap(in);
|
||||
}
|
||||
else {
|
||||
return in;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
215
common/net/eqstream.cpp
Normal file
215
common/net/eqstream.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
#include "eqstream.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
|
||||
EQ::Net::EQStreamManager::EQStreamManager(EQStreamManagerOptions &options) : m_daybreak(options.daybreak_options)
|
||||
{
|
||||
m_options = options;
|
||||
|
||||
m_daybreak.OnNewConnection(std::bind(&EQStreamManager::DaybreakNewConnection, this, std::placeholders::_1));
|
||||
m_daybreak.OnConnectionStateChange(std::bind(&EQStreamManager::DaybreakConnectionStateChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
m_daybreak.OnPacketRecv(std::bind(&EQStreamManager::DaybreakPacketRecv, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
EQ::Net::EQStreamManager::~EQStreamManager()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::EQStreamManager::DaybreakNewConnection(std::shared_ptr<DaybreakConnection> connection)
|
||||
{
|
||||
std::shared_ptr<EQStream> stream(new EQStream(this, connection));
|
||||
m_streams.insert(std::make_pair(connection, stream));
|
||||
if (m_on_new_connection) {
|
||||
m_on_new_connection(stream);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::EQStreamManager::DaybreakConnectionStateChange(std::shared_ptr<DaybreakConnection> connection, DbProtocolStatus from, DbProtocolStatus to)
|
||||
{
|
||||
auto iter = m_streams.find(connection);
|
||||
if (iter != m_streams.end()) {
|
||||
if (m_on_connection_state_change) {
|
||||
m_on_connection_state_change(iter->second, from, to);
|
||||
}
|
||||
|
||||
if (to == EQ::Net::StatusDisconnected) {
|
||||
m_streams.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::EQStreamManager::DaybreakPacketRecv(std::shared_ptr<DaybreakConnection> connection, const Packet &p)
|
||||
{
|
||||
auto iter = m_streams.find(connection);
|
||||
if (iter != m_streams.end()) {
|
||||
auto &stream = iter->second;
|
||||
if (stream->m_opcode_manager && stream->m_opcode_manager) {
|
||||
std::unique_ptr<EQ::Net::Packet> t(new EQ::Net::WritablePacket());
|
||||
t->PutPacket(0, p);
|
||||
stream->m_packet_queue.push_back(std::move(t));
|
||||
|
||||
if (m_on_data_avail) {
|
||||
m_on_data_avail(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EQ::Net::EQStream::EQStream(EQStreamManager *owner, std::shared_ptr<DaybreakConnection> connection)
|
||||
{
|
||||
m_owner = owner;
|
||||
m_connection = connection;
|
||||
}
|
||||
|
||||
EQ::Net::EQStream::~EQStream()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
|
||||
if (m_opcode_manager && *m_opcode_manager) {
|
||||
uint16 opcode = 0;
|
||||
if (p->GetOpcodeBypass() != 0) {
|
||||
opcode = p->GetOpcodeBypass();
|
||||
}
|
||||
else {
|
||||
opcode = (*m_opcode_manager)->EmuToEQ(p->GetOpcode());
|
||||
}
|
||||
|
||||
EQ::Net::WritablePacket out;
|
||||
switch (m_owner->m_options.opcode_size) {
|
||||
case 1:
|
||||
out.PutUInt8(0, opcode);
|
||||
out.PutData(1, p->pBuffer, p->size);
|
||||
break;
|
||||
case 2:
|
||||
out.PutUInt16(0, opcode);
|
||||
out.PutData(2, p->pBuffer, p->size);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ack_req) {
|
||||
m_connection->QueuePacket(out, 0, false);
|
||||
}
|
||||
else {
|
||||
m_connection->QueuePacket(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req) {
|
||||
QueuePacket(*p, ack_req);
|
||||
delete *p;
|
||||
*p = nullptr;
|
||||
}
|
||||
|
||||
EQApplicationPacket *EQ::Net::EQStream::PopPacket() {
|
||||
if (m_packet_queue.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_opcode_manager != nullptr && *m_opcode_manager != nullptr) {
|
||||
auto &p = m_packet_queue.front();
|
||||
|
||||
uint16 opcode = 0;
|
||||
switch (m_owner->m_options.opcode_size) {
|
||||
case 1:
|
||||
opcode = p->GetUInt8(0);
|
||||
break;
|
||||
case 2:
|
||||
opcode = p->GetUInt16(0);
|
||||
break;
|
||||
}
|
||||
|
||||
EmuOpcode emu_op = (*m_opcode_manager)->EQToEmu(opcode);
|
||||
EQApplicationPacket *ret = new EQApplicationPacket(emu_op, (unsigned char*)p->Data(), p->Length() - m_owner->m_options.opcode_size);
|
||||
m_packet_queue.pop_front();
|
||||
return ret;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void EQ::Net::EQStream::Close() {
|
||||
m_connection->Close();
|
||||
}
|
||||
|
||||
uint32 EQ::Net::EQStream::GetRemoteIP() const {
|
||||
return inet_addr(RemoteEndpoint().c_str());
|
||||
}
|
||||
|
||||
bool EQ::Net::EQStream::CheckState(EQStreamState state) {
|
||||
return GetState() == state;
|
||||
}
|
||||
|
||||
EQStreamInterface::MatchState EQ::Net::EQStream::CheckSignature(const Signature *sig) {
|
||||
if (!m_packet_queue.empty()) {
|
||||
auto p = m_packet_queue.front().get();
|
||||
uint16 opcode = 0;
|
||||
size_t length = p->Length() - m_owner->m_options.opcode_size;
|
||||
switch (m_owner->m_options.opcode_size) {
|
||||
case 1:
|
||||
opcode = p->GetUInt8(0);
|
||||
break;
|
||||
case 2:
|
||||
opcode = p->GetUInt16(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sig->ignore_eq_opcode != 0 && opcode == sig->ignore_eq_opcode) {
|
||||
if (m_packet_queue.size() > 1) {
|
||||
p = m_packet_queue[1].get();
|
||||
opcode = 0;
|
||||
length = p->Length() - m_owner->m_options.opcode_size;
|
||||
switch (m_owner->m_options.opcode_size) {
|
||||
case 1:
|
||||
opcode = p->GetUInt8(0);
|
||||
break;
|
||||
case 2:
|
||||
opcode = p->GetUInt16(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return MatchNotReady;
|
||||
}
|
||||
}
|
||||
|
||||
if (opcode == sig->first_eq_opcode) {
|
||||
if (length == sig->first_length) {
|
||||
Log.OutF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode matched {2:#x} and length matched {3}",
|
||||
RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode, length);
|
||||
return MatchSuccessful;
|
||||
}
|
||||
else if(length == 0) {
|
||||
Log.OutF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode matched {2:#x} and length is ignored.",
|
||||
RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode);
|
||||
return MatchSuccessful;
|
||||
}
|
||||
else {
|
||||
Log.OutF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode matched {2:#x} but length {3} did not match expected {4}",
|
||||
RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode, length, sig->first_length);
|
||||
return MatchFailed;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log.OutF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode {1:#x} did not match expected {2:#x}",
|
||||
RemoteEndpoint(), m_connection->RemotePort(), opcode, sig->first_eq_opcode);
|
||||
return MatchFailed;
|
||||
}
|
||||
}
|
||||
|
||||
return MatchNotReady;
|
||||
}
|
||||
|
||||
EQStreamState EQ::Net::EQStream::GetState() {
|
||||
auto status = m_connection->GetStatus();
|
||||
switch (status) {
|
||||
case StatusConnecting:
|
||||
return UNESTABLISHED;
|
||||
case StatusConnected:
|
||||
return ESTABLISHED;
|
||||
case StatusDisconnecting:
|
||||
return DISCONNECTING;
|
||||
default:
|
||||
return CLOSED;
|
||||
}
|
||||
}
|
||||
101
common/net/eqstream.h
Normal file
101
common/net/eqstream.h
Normal file
@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
#include "../eq_packet.h"
|
||||
#include "../eq_stream_intf.h"
|
||||
#include "../opcodemgr.h"
|
||||
#include "daybreak_connection.h"
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
struct EQStreamManagerOptions
|
||||
{
|
||||
EQStreamManagerOptions() {
|
||||
opcode_size = 2;
|
||||
}
|
||||
|
||||
EQStreamManagerOptions(bool encoded, bool compressed) {
|
||||
opcode_size = 2;
|
||||
if (encoded) {
|
||||
daybreak_options.encode_passes[0] = EncodeXOR;
|
||||
|
||||
if (compressed) {
|
||||
daybreak_options.encode_passes[1] = EncodeCompression;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (compressed) {
|
||||
daybreak_options.encode_passes[0] = EncodeCompression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int opcode_size;
|
||||
DaybreakConnectionManagerOptions daybreak_options;
|
||||
};
|
||||
|
||||
class EQStream;
|
||||
class EQStreamManager
|
||||
{
|
||||
public:
|
||||
EQStreamManager(EQStreamManagerOptions &options);
|
||||
~EQStreamManager();
|
||||
|
||||
void OnNewConnection(std::function<void(std::shared_ptr<EQStream>)> func) { m_on_new_connection = func; }
|
||||
void OnConnectionStateChange(std::function<void(std::shared_ptr<EQStream>, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; }
|
||||
void OnDataAvailable(std::function<void(std::shared_ptr<EQStream>)> func) { m_on_data_avail = func; }
|
||||
|
||||
private:
|
||||
EQStreamManagerOptions m_options;
|
||||
DaybreakConnectionManager m_daybreak;
|
||||
std::function<void(std::shared_ptr<EQStream>)> m_on_new_connection;
|
||||
std::function<void(std::shared_ptr<EQStream>, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change;
|
||||
std::function<void(std::shared_ptr<EQStream>)> m_on_data_avail;
|
||||
std::map<std::shared_ptr<DaybreakConnection>, std::shared_ptr<EQStream>> m_streams;
|
||||
|
||||
void DaybreakNewConnection(std::shared_ptr<DaybreakConnection> connection);
|
||||
void DaybreakConnectionStateChange(std::shared_ptr<DaybreakConnection> connection, DbProtocolStatus from, DbProtocolStatus to);
|
||||
void DaybreakPacketRecv(std::shared_ptr<DaybreakConnection> connection, const Packet &p);
|
||||
friend class EQStream;
|
||||
};
|
||||
|
||||
class EQStream : public EQStreamInterface
|
||||
{
|
||||
public:
|
||||
EQStream(EQStreamManager *parent, std::shared_ptr<DaybreakConnection> connection);
|
||||
~EQStream();
|
||||
|
||||
virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req = true);
|
||||
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req = true);
|
||||
virtual EQApplicationPacket *PopPacket();
|
||||
virtual void Close();
|
||||
virtual void ReleaseFromUse() { };
|
||||
virtual void RemoveData() { };
|
||||
virtual uint32 GetRemoteIP() const;
|
||||
//the code is dumb and assumes this is in network order...
|
||||
virtual uint16 GetRemotePort() const { return EQ::Net::HostToNetwork(m_connection->RemotePort()); }
|
||||
virtual bool CheckState(EQStreamState state);
|
||||
virtual std::string Describe() const { return "Direct EQStream"; }
|
||||
virtual void SetActive(bool val) { }
|
||||
virtual MatchState CheckSignature(const Signature *sig);
|
||||
virtual EQStreamState GetState();
|
||||
virtual void SetOpcodeManager(OpcodeManager **opm) {
|
||||
m_opcode_manager = opm;
|
||||
}
|
||||
|
||||
const std::string& RemoteEndpoint() const { return m_connection->RemoteEndpoint(); }
|
||||
const DaybreakConnectionStats& GetStats() const { return m_connection->GetStats(); }
|
||||
void ResetStats() { m_connection->ResetStats(); }
|
||||
size_t GetRollingPing() const { return m_connection->GetRollingPing(); }
|
||||
private:
|
||||
EQStreamManager *m_owner;
|
||||
std::shared_ptr<DaybreakConnection> m_connection;
|
||||
OpcodeManager **m_opcode_manager;
|
||||
std::deque<std::unique_ptr<EQ::Net::Packet>> m_packet_queue;
|
||||
friend class EQStreamManager;
|
||||
};
|
||||
}
|
||||
}
|
||||
332
common/net/packet.cpp
Normal file
332
common/net/packet.cpp
Normal file
@ -0,0 +1,332 @@
|
||||
#include "packet.h"
|
||||
#include "endian.h"
|
||||
#include <fmt/format.h>
|
||||
#include <cctype>
|
||||
|
||||
void EQ::Net::Packet::PutInt8(size_t offset, int8_t value)
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
if (!Resize(offset + 1)) {
|
||||
throw std::out_of_range("Packet::PutInt8(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(int8_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutInt16(size_t offset, int16_t value)
|
||||
{
|
||||
if (Length() < offset + 2) {
|
||||
if (!Resize(offset + 2)) {
|
||||
throw std::out_of_range("Packet::PutInt16(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(int16_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutInt32(size_t offset, int32_t value)
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
if (!Resize(offset + 4)) {
|
||||
throw std::out_of_range("Packet::PutInt32(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(int32_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutInt64(size_t offset, int64_t value)
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
if (!Resize(offset + 8)) {
|
||||
throw std::out_of_range("Packet::PutInt64(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(int64_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutUInt8(size_t offset, uint8_t value)
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
if (!Resize(offset + 1)) {
|
||||
throw std::out_of_range("Packet::PutUInt8(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(uint8_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutUInt16(size_t offset, uint16_t value)
|
||||
{
|
||||
if (Length() < offset + 2) {
|
||||
if (!Resize(offset + 2)) {
|
||||
throw std::out_of_range("Packet::PutUInt16(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(uint16_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutUInt32(size_t offset, uint32_t value)
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
if (!Resize(offset + 4)) {
|
||||
throw std::out_of_range("Packet::PutUInt32(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(uint32_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutUInt64(size_t offset, uint64_t value)
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
if (!Resize(offset + 8)) {
|
||||
throw std::out_of_range("Packet::PutUInt64(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(uint64_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutFloat(size_t offset, float value)
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
if (!Resize(offset + 4)) {
|
||||
throw std::out_of_range("Packet::PutFloat(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(float*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutDouble(size_t offset, double value)
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
if (!Resize(offset + 8)) {
|
||||
throw std::out_of_range("Packet::PutDouble(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(double*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutString(size_t offset, const std::string &str)
|
||||
{
|
||||
if (Length() < offset + str.length()) {
|
||||
if (!Resize(offset + str.length())) {
|
||||
throw std::out_of_range("Packet::PutString(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(((char*)Data() + offset), str.c_str(), str.length());
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutCString(size_t offset, const char *str)
|
||||
{
|
||||
size_t sz = strlen(str);
|
||||
if (Length() < offset + sz + 1) {
|
||||
if (!Resize(offset + sz + 1)) {
|
||||
throw std::out_of_range("Packet::PutCString(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(((char*)Data() + offset), str, sz);
|
||||
*((char*)Data() + offset + sz) = 0;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutPacket(size_t offset, const Packet &p)
|
||||
{
|
||||
if (Length() < offset + p.Length()) {
|
||||
if (!Resize(offset + p.Length())) {
|
||||
throw std::out_of_range("Packet::PutPacket(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(((char*)Data() + offset), p.Data(), p.Length());
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutData(size_t offset, void *data, size_t length)
|
||||
{
|
||||
if (Length() < offset + length) {
|
||||
if (!Resize(offset + length)) {
|
||||
throw std::out_of_range("Packet::PutData(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(((char*)Data() + offset), data, length);
|
||||
}
|
||||
|
||||
int8_t EQ::Net::Packet::GetInt8(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(int8_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
int16_t EQ::Net::Packet::GetInt16(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 2) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(int16_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
int32_t EQ::Net::Packet::GetInt32(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(int32_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
int64_t EQ::Net::Packet::GetInt64(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(int64_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
uint8_t EQ::Net::Packet::GetUInt8(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(uint8_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
uint16_t EQ::Net::Packet::GetUInt16(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 2) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(uint16_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
uint32_t EQ::Net::Packet::GetUInt32(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(uint32_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
uint64_t EQ::Net::Packet::GetUInt64(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(uint64_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
float EQ::Net::Packet::GetFloat(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(float*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
double EQ::Net::Packet::GetDouble(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(double*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
std::string EQ::Net::Packet::GetString(size_t offset, size_t length) const
|
||||
{
|
||||
if (Length() < offset + length) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return std::string((char*)Data(), (char*)Data() + length);
|
||||
}
|
||||
|
||||
std::string EQ::Net::Packet::GetCString(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
char *str = ((char*)Data() + offset);
|
||||
return std::string(str);
|
||||
}
|
||||
|
||||
char ToSafePrint(unsigned char in) {
|
||||
if (std::isprint(in)) {
|
||||
return in;
|
||||
}
|
||||
|
||||
return '.';
|
||||
}
|
||||
|
||||
std::string EQ::Net::Packet::ToString() const
|
||||
{
|
||||
return ToString(16);
|
||||
}
|
||||
|
||||
std::string EQ::Net::Packet::ToString(size_t line_length) const
|
||||
{
|
||||
std::string ret;
|
||||
size_t lines = Length() / line_length;
|
||||
size_t i;
|
||||
|
||||
char *data = (char*)Data();
|
||||
|
||||
for (i = 0; i < lines; ++i) {
|
||||
ret += fmt::format("{:0>5x} |", i * line_length);
|
||||
std::string hex;
|
||||
std::string ascii;
|
||||
for (size_t j = 0; j < line_length; ++j) {
|
||||
hex += fmt::format(" {:0>2x}", (uint8_t)data[(i * line_length) + j]);
|
||||
ascii += fmt::format("{}", ToSafePrint(data[(i * line_length) + j]));
|
||||
}
|
||||
|
||||
ret += hex;
|
||||
ret += " | ";
|
||||
ret += ascii;
|
||||
ret += "\n";
|
||||
}
|
||||
|
||||
if (Length() % line_length > 0) {
|
||||
ret += fmt::format("{:0>5x} |", i * line_length);
|
||||
|
||||
size_t non_blank_count = Length() % line_length;
|
||||
size_t blank_count = line_length - non_blank_count;
|
||||
std::string hex;
|
||||
std::string ascii;
|
||||
|
||||
for (size_t j = 0; j < non_blank_count; ++j) {
|
||||
hex += fmt::format(" {:0>2x}", (uint8_t)data[(i * line_length) + j]);
|
||||
ascii += fmt::format("{}", ToSafePrint(data[(i * line_length) + j]));
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < blank_count; ++j) {
|
||||
hex += " ";
|
||||
ascii += " ";
|
||||
}
|
||||
|
||||
ret += hex;
|
||||
ret += " | ";
|
||||
ret += ascii;
|
||||
ret += "\n";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
131
common/net/packet.h
Normal file
131
common/net/packet.h
Normal file
@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
#include "../util/memory_stream.h"
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/archives/binary.hpp>
|
||||
|
||||
namespace EQ {
|
||||
namespace Net {
|
||||
class Packet
|
||||
{
|
||||
public:
|
||||
Packet() { }
|
||||
virtual ~Packet() { }
|
||||
|
||||
virtual const void *Data() const = 0;
|
||||
virtual void *Data() = 0;
|
||||
virtual size_t Length() const = 0;
|
||||
virtual size_t Length() = 0;
|
||||
virtual bool Clear() = 0;
|
||||
virtual bool Resize(size_t new_size) = 0;
|
||||
virtual void Reserve(size_t new_size) = 0;
|
||||
|
||||
template<typename T>
|
||||
T GetSerialize(size_t offset) const
|
||||
{
|
||||
if (T::size() > (Length() - offset)) {
|
||||
throw std::out_of_range("Packet::GetSerialize(), packet not large enough to cast to type.");
|
||||
}
|
||||
|
||||
T ret;
|
||||
Util::MemoryStreamReader reader(((char*)Data() + offset), Length());
|
||||
cereal::BinaryInputArchive input(reader);
|
||||
input(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PutSerialize(size_t offset, const T &value) {
|
||||
std::stringstream buffer(std::ios::in | std::ios::out | std::ios::binary);
|
||||
cereal::BinaryOutputArchive output(buffer);
|
||||
output(value);
|
||||
|
||||
auto str = buffer.str();
|
||||
if (Length() < offset + str.length()) {
|
||||
if (!Resize(offset + str.length())) {
|
||||
throw std::out_of_range("Packet::PutSerialize(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy((char*)Data() + offset, &str[0], str.length());
|
||||
}
|
||||
|
||||
void PutInt8(size_t offset, int8_t value);
|
||||
void PutInt16(size_t offset, int16_t value);
|
||||
void PutInt32(size_t offset, int32_t value);
|
||||
void PutInt64(size_t offset, int64_t value);
|
||||
void PutUInt8(size_t offset, uint8_t value);
|
||||
void PutUInt16(size_t offset, uint16_t value);
|
||||
void PutUInt32(size_t offset, uint32_t value);
|
||||
void PutUInt64(size_t offset, uint64_t value);
|
||||
void PutFloat(size_t offset, float value);
|
||||
void PutDouble(size_t offset, double value);
|
||||
void PutString(size_t offset, const std::string &str);
|
||||
void PutCString(size_t offset, const char *str);
|
||||
void PutPacket(size_t offset, const Packet &p);
|
||||
void PutData(size_t offset, void *data, size_t length);
|
||||
|
||||
int8_t GetInt8(size_t offset) const;
|
||||
int16_t GetInt16(size_t offset) const;
|
||||
int32_t GetInt32(size_t offset) const;
|
||||
int64_t GetInt64(size_t offset) const;
|
||||
uint8_t GetUInt8(size_t offset) const;
|
||||
uint16_t GetUInt16(size_t offset) const;
|
||||
uint32_t GetUInt32(size_t offset) const;
|
||||
uint64_t GetUInt64(size_t offset) const;
|
||||
float GetFloat(size_t offset) const;
|
||||
double GetDouble(size_t offset) const;
|
||||
std::string GetString(size_t offset, size_t length) const;
|
||||
std::string GetCString(size_t offset) const;
|
||||
|
||||
std::string ToString() const;
|
||||
std::string ToString(size_t line_length) const;
|
||||
};
|
||||
|
||||
class ReadOnlyPacket : public Packet
|
||||
{
|
||||
public:
|
||||
ReadOnlyPacket(void *data, size_t size) { m_data = data; m_data_length = size; }
|
||||
virtual ~ReadOnlyPacket() { }
|
||||
ReadOnlyPacket(const ReadOnlyPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; }
|
||||
ReadOnlyPacket& operator=(const ReadOnlyPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; return *this; }
|
||||
ReadOnlyPacket(ReadOnlyPacket &&o) { m_data = o.m_data; m_data_length = o.m_data_length; }
|
||||
|
||||
virtual const void *Data() const { return m_data; }
|
||||
virtual void *Data() { return m_data; }
|
||||
virtual size_t Length() const { return m_data_length; }
|
||||
virtual size_t Length() { return m_data_length; }
|
||||
virtual bool Clear() { return false; }
|
||||
virtual bool Resize(size_t new_size) { return false; }
|
||||
virtual void Reserve(size_t new_size) { }
|
||||
|
||||
protected:
|
||||
void *m_data;
|
||||
size_t m_data_length;
|
||||
};
|
||||
|
||||
class WritablePacket : public Packet
|
||||
{
|
||||
public:
|
||||
WritablePacket() { }
|
||||
virtual ~WritablePacket() { }
|
||||
WritablePacket(WritablePacket &&o) { m_data = std::move(o.m_data); }
|
||||
WritablePacket(const WritablePacket &o) { m_data = o.m_data; }
|
||||
WritablePacket& operator=(const WritablePacket &o) { m_data = o.m_data; return *this; }
|
||||
|
||||
virtual const void *Data() const { return &m_data[0]; }
|
||||
virtual void *Data() { return &m_data[0]; }
|
||||
virtual size_t Length() const { return m_data.size(); }
|
||||
virtual size_t Length() { return m_data.size(); }
|
||||
virtual bool Clear() { m_data.clear(); return true; }
|
||||
virtual bool Resize(size_t new_size) { m_data.resize(new_size); return true; }
|
||||
virtual void Reserve(size_t new_size) { m_data.reserve(new_size); }
|
||||
protected:
|
||||
std::vector<char> m_data;
|
||||
};
|
||||
}
|
||||
}
|
||||
31
common/util/memory_stream.h
Normal file
31
common/util/memory_stream.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <streambuf>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Util {
|
||||
class MemoryBuffer : public std::streambuf
|
||||
{
|
||||
public:
|
||||
MemoryBuffer(char* base, size_t size) {
|
||||
setg(base, base, base + size);
|
||||
setp(base, base + size);
|
||||
}
|
||||
};
|
||||
|
||||
class MemoryStreamWriter : virtual MemoryBuffer, public std::ostream
|
||||
{
|
||||
public:
|
||||
MemoryStreamWriter(char* base, size_t size) : MemoryBuffer(base, size), std::ostream(static_cast<std::streambuf*>(this)) { }
|
||||
};
|
||||
|
||||
class MemoryStreamReader : virtual MemoryBuffer, public std::istream
|
||||
{
|
||||
public:
|
||||
MemoryStreamReader(char* base, size_t size) : MemoryBuffer(base, size), std::istream(static_cast<std::streambuf*>(this)) { }
|
||||
};
|
||||
}
|
||||
}
|
||||
189
common/util/uuid.cpp
Normal file
189
common/util/uuid.cpp
Normal file
@ -0,0 +1,189 @@
|
||||
#include "uuid.h"
|
||||
|
||||
#include <core/logsys.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <objbase.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <uuid/uuid.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CFUUID.h>
|
||||
#endif
|
||||
|
||||
unsigned char hexDigitToChar(char ch)
|
||||
{
|
||||
if (ch > 47 && ch < 58)
|
||||
return ch - 48;
|
||||
|
||||
if (ch > 96 && ch < 103)
|
||||
return ch - 87;
|
||||
|
||||
if (ch > 64 && ch < 71)
|
||||
return ch - 55;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char hexPairToChar(char a, char b)
|
||||
{
|
||||
return hexDigitToChar(a) * 16 + hexDigitToChar(b);
|
||||
}
|
||||
|
||||
EQ::Util::UUID::UUID()
|
||||
{
|
||||
m_bytes = std::vector<char>(16, 0);
|
||||
}
|
||||
|
||||
EQ::Util::UUID::UUID(const unsigned char *bytes)
|
||||
{
|
||||
m_bytes.assign(bytes, bytes + 16);
|
||||
}
|
||||
|
||||
EQ::Util::UUID::UUID(const UUID &o)
|
||||
{
|
||||
m_bytes = o.m_bytes;
|
||||
}
|
||||
|
||||
EQ::Util::UUID::UUID(UUID &&o)
|
||||
{
|
||||
std::swap(m_bytes, o.m_bytes);
|
||||
}
|
||||
|
||||
EQ::Util::UUID& EQ::Util::UUID::operator=(const UUID &o)
|
||||
{
|
||||
m_bytes = o.m_bytes;
|
||||
return *this;
|
||||
}
|
||||
|
||||
EQ::Util::UUID::~UUID()
|
||||
{
|
||||
}
|
||||
|
||||
EQ::Util::UUID EQ::Util::UUID::Generate()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
GUID id;
|
||||
CoCreateGuid(&id);
|
||||
|
||||
const unsigned char buffer[16] =
|
||||
{
|
||||
static_cast<unsigned char>((id.Data1 >> 24) & 0xFF),
|
||||
static_cast<unsigned char>((id.Data1 >> 16) & 0xFF),
|
||||
static_cast<unsigned char>((id.Data1 >> 8) & 0xFF),
|
||||
static_cast<unsigned char>((id.Data1) & 0xff),
|
||||
static_cast<unsigned char>((id.Data2 >> 8) & 0xFF),
|
||||
static_cast<unsigned char>((id.Data2) & 0xff),
|
||||
static_cast<unsigned char>((id.Data3 >> 8) & 0xFF),
|
||||
static_cast<unsigned char>((id.Data3) & 0xFF),
|
||||
id.Data4[0],
|
||||
id.Data4[1],
|
||||
id.Data4[2],
|
||||
id.Data4[3],
|
||||
id.Data4[4],
|
||||
id.Data4[5],
|
||||
id.Data4[6],
|
||||
id.Data4[7]
|
||||
};
|
||||
|
||||
return buffer;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
uuid_t id;
|
||||
uuid_generate(id);
|
||||
return id;
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
auto id = CFUUIDCreate(nullptr);
|
||||
auto bytes = CFUUIDGetUUIDBytes(id);
|
||||
|
||||
const unsigned char buffer[16] =
|
||||
{
|
||||
bytes.byte0,
|
||||
bytes.byte1,
|
||||
bytes.byte2,
|
||||
bytes.byte3,
|
||||
bytes.byte4,
|
||||
bytes.byte5,
|
||||
bytes.byte6,
|
||||
bytes.byte7,
|
||||
bytes.byte8,
|
||||
bytes.byte9,
|
||||
bytes.byte10,
|
||||
bytes.byte11,
|
||||
bytes.byte12,
|
||||
bytes.byte13,
|
||||
bytes.byte14,
|
||||
bytes.byte15
|
||||
};
|
||||
|
||||
CFRelease(id);
|
||||
|
||||
return buffer;
|
||||
#endif
|
||||
}
|
||||
|
||||
EQ::Util::UUID EQ::Util::UUID::FromString(const std::string &str)
|
||||
{
|
||||
UUID ret;
|
||||
ret.m_bytes.clear();
|
||||
|
||||
size_t i = 0;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EQ::Util::UUID EQ::Util::UUID::FromByteArray(const char *buffer)
|
||||
{
|
||||
return UUID((unsigned char*)buffer);
|
||||
}
|
||||
|
||||
std::string EQ::Util::UUID::ToString() const
|
||||
{
|
||||
return fmt::format("{:0<2x}{:0<2x}{:0<2x}{:0<2x}-{:0<2x}{:0<2x}-{:0<2x}{:0<2x}-{:0<2x}{:0<2x}-{:0<2x}{:0<2x}{:0<2x}{:0<2x}{:0<2x}{:0<2x}",
|
||||
(unsigned char)m_bytes[0],
|
||||
(unsigned char)m_bytes[1],
|
||||
(unsigned char)m_bytes[2],
|
||||
(unsigned char)m_bytes[3],
|
||||
(unsigned char)m_bytes[4],
|
||||
(unsigned char)m_bytes[5],
|
||||
(unsigned char)m_bytes[6],
|
||||
(unsigned char)m_bytes[7],
|
||||
(unsigned char)m_bytes[8],
|
||||
(unsigned char)m_bytes[9],
|
||||
(unsigned char)m_bytes[10],
|
||||
(unsigned char)m_bytes[11],
|
||||
(unsigned char)m_bytes[12],
|
||||
(unsigned char)m_bytes[13],
|
||||
(unsigned char)m_bytes[14],
|
||||
(unsigned char)m_bytes[15]);
|
||||
}
|
||||
|
||||
const std::vector<char>& EQ::Util::UUID::ToByteArray() const
|
||||
{
|
||||
return m_bytes;
|
||||
}
|
||||
35
common/util/uuid.h
Normal file
35
common/util/uuid.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ios>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Util
|
||||
{
|
||||
class UUID
|
||||
{
|
||||
public:
|
||||
UUID(const UUID &o);
|
||||
UUID(UUID &&o);
|
||||
UUID& operator=(const UUID &o);
|
||||
~UUID();
|
||||
|
||||
static UUID Generate();
|
||||
static UUID FromString(const std::string &str);
|
||||
static UUID FromByteArray(const char *buffer);
|
||||
|
||||
std::string ToString() const;
|
||||
const std::vector<char>& ToByteArray() const;
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const UUID &id) {
|
||||
return os << id.ToString();
|
||||
}
|
||||
private:
|
||||
UUID();
|
||||
UUID(const unsigned char *bytes);
|
||||
std::vector<char> m_bytes;
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -13,7 +13,7 @@ SET(eqlaunch_headers
|
||||
|
||||
ADD_EXECUTABLE(eqlaunch ${eqlaunch_sources} ${eqlaunch_headers})
|
||||
|
||||
INSTALL(TARGETS eqlaunch RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
INSTALL(TARGETS eqlaunch RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(eqlaunch common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY})
|
||||
|
||||
|
||||
6
libs/CMakeLists.txt
Normal file
6
libs/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
IF(EQEMU_BUILD_LUA)
|
||||
ADD_SUBDIRECTORY(luabind)
|
||||
ENDIF(EQEMU_BUILD_LUA)
|
||||
|
||||
ADD_SUBDIRECTORY(libuv)
|
||||
ADD_SUBDIRECTORY(format)
|
||||
427
libs/cereal/cereal/access.hpp
Normal file
427
libs/cereal/cereal/access.hpp
Normal file
@ -0,0 +1,427 @@
|
||||
/*! \file access.hpp
|
||||
\brief Access control, default construction, and serialization disambiguation */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_ACCESS_HPP_
|
||||
#define CEREAL_ACCESS_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
|
||||
#include <cereal/macros.hpp>
|
||||
#include <cereal/details/helpers.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// ######################################################################
|
||||
//! A class that allows cereal to load smart pointers to types that have no default constructor
|
||||
/*! If your class does not have a default constructor, cereal will not be able
|
||||
to load any smart pointers to it unless you overload LoadAndConstruct
|
||||
for your class, and provide an appropriate load_and_construct method. You can also
|
||||
choose to define a member static function instead of specializing this class.
|
||||
|
||||
The specialization of LoadAndConstruct must be placed within the cereal namespace:
|
||||
|
||||
@code{.cpp}
|
||||
struct MyType
|
||||
{
|
||||
MyType( int x ); // note: no default ctor
|
||||
int myX;
|
||||
|
||||
// Define a serialize or load/save pair as you normally would
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( myX );
|
||||
}
|
||||
};
|
||||
|
||||
// Provide a specialization for LoadAndConstruct for your type
|
||||
namespace cereal
|
||||
{
|
||||
template <> struct LoadAndConstruct<MyType>
|
||||
{
|
||||
// load_and_construct will be passed the archive that you will be loading
|
||||
// from as well as a construct object which you can use as if it were the
|
||||
// constructor for your type. cereal will handle all memory management for you.
|
||||
template <class Archive>
|
||||
static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
|
||||
{
|
||||
int x;
|
||||
ar( x );
|
||||
construct( x );
|
||||
}
|
||||
};
|
||||
} // end namespace cereal
|
||||
@endcode
|
||||
|
||||
Please note that just as in using external serialization functions, you cannot get
|
||||
access to non-public members of your class by befriending cereal::access. If you
|
||||
have the ability to modify the class you wish to serialize, it is recommended that you
|
||||
use member serialize functions and a static member load_and_construct function.
|
||||
|
||||
@tparam T The type to specialize for
|
||||
@ingroup Access */
|
||||
template <class T>
|
||||
struct LoadAndConstruct
|
||||
{
|
||||
//! Called by cereal if no default constructor exists to load and construct data simultaneously
|
||||
/*! Overloads of this should return a pointer to T and expect an archive as a parameter */
|
||||
static std::false_type load_and_construct(...)
|
||||
{ return std::false_type(); }
|
||||
};
|
||||
|
||||
// forward decl for construct
|
||||
//! @cond PRIVATE_NEVERDEFINED
|
||||
namespace memory_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
|
||||
//! @endcond
|
||||
|
||||
//! Used to construct types with no default constructor
|
||||
/*! When serializing a type that has no default constructor, cereal
|
||||
will attempt to call either the class static function load_and_construct
|
||||
or the appropriate template specialization of LoadAndConstruct. cereal
|
||||
will pass that function a reference to the archive as well as a reference
|
||||
to a construct object which should be used to perform the allocation once
|
||||
data has been appropriately loaded.
|
||||
|
||||
@code{.cpp}
|
||||
struct MyType
|
||||
{
|
||||
// note the lack of default constructor
|
||||
MyType( int xx, int yy );
|
||||
|
||||
int x, y;
|
||||
double notInConstructor;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( x, y );
|
||||
ar( notInConstructor );
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
|
||||
{
|
||||
int x, y;
|
||||
ar( x, y );
|
||||
|
||||
// use construct object to initialize with loaded data
|
||||
construct( x, y );
|
||||
|
||||
// access to member variables and functions via -> operator
|
||||
ar( construct->notInConstructor );
|
||||
|
||||
// could also do the above section by:
|
||||
double z;
|
||||
ar( z );
|
||||
construct->notInConstructor = z;
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
@tparam T The class type being serialized
|
||||
*/
|
||||
template <class T>
|
||||
class construct
|
||||
{
|
||||
public:
|
||||
//! Construct and initialize the type T with the given arguments
|
||||
/*! This will forward all arguments to the underlying type T,
|
||||
calling an appropriate constructor.
|
||||
|
||||
Calling this function more than once will result in an exception
|
||||
being thrown.
|
||||
|
||||
@param args The arguments to the constructor for T
|
||||
@throw Exception If called more than once */
|
||||
template <class ... Args>
|
||||
void operator()( Args && ... args );
|
||||
// implementation deferred due to reliance on cereal::access
|
||||
|
||||
//! Get a reference to the initialized underlying object
|
||||
/*! This must be called after the object has been initialized.
|
||||
|
||||
@return A reference to the initialized object
|
||||
@throw Exception If called before initialization */
|
||||
T * operator->()
|
||||
{
|
||||
if( !itsValid )
|
||||
throw Exception("Object must be initialized prior to accessing members");
|
||||
|
||||
return itsPtr;
|
||||
}
|
||||
|
||||
//! Returns a raw pointer to the initialized underlying object
|
||||
/*! This is mainly intended for use with passing an instance of
|
||||
a constructed object to cereal::base_class.
|
||||
|
||||
It is strongly recommended to avoid using this function in
|
||||
any other circumstance.
|
||||
|
||||
@return A raw pointer to the initialized type */
|
||||
T * ptr()
|
||||
{
|
||||
return operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
template <class A, class B> friend struct ::cereal::memory_detail::LoadAndConstructLoadWrapper;
|
||||
|
||||
construct( T * p ) : itsPtr( p ), itsValid( false ) {}
|
||||
construct( construct const & ) = delete;
|
||||
construct & operator=( construct const & ) = delete;
|
||||
|
||||
T * itsPtr;
|
||||
bool itsValid;
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
//! A class that can be made a friend to give cereal access to non public functions
|
||||
/*! If you desire non-public serialization functions within a class, cereal can only
|
||||
access these if you declare cereal::access a friend.
|
||||
|
||||
@code{.cpp}
|
||||
class MyClass
|
||||
{
|
||||
private:
|
||||
friend class cereal::access; // gives access to the private serialize
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
// some code
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
@ingroup Access */
|
||||
class access
|
||||
{
|
||||
public:
|
||||
// ####### Standard Serialization ########################################
|
||||
template<class Archive, class T> inline
|
||||
static auto member_serialize(Archive & ar, T & t) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save(Archive & ar, T const & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save_non_const(Archive & ar, T & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_load(Archive & ar, T & t) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_LOAD_FUNCTION_NAME(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save_minimal(Archive const & ar, T const & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save_minimal_non_const(Archive const & ar, T & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
|
||||
|
||||
template<class Archive, class T, class U> inline
|
||||
static auto member_load_minimal(Archive const & ar, T & t, U && u) -> decltype(t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)))
|
||||
{ return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)); }
|
||||
|
||||
// ####### Versioned Serialization #######################################
|
||||
template<class Archive, class T> inline
|
||||
static auto member_serialize(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save(Archive & ar, T const & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save_non_const(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_load(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_LOAD_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save_minimal(Archive const & ar, T const & t, const std::uint32_t version) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save_minimal_non_const(Archive const & ar, T & t, const std::uint32_t version) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T, class U> inline
|
||||
static auto member_load_minimal(Archive const & ar, T & t, U && u, const std::uint32_t version) -> decltype(t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u), version))
|
||||
{ return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u), version); }
|
||||
|
||||
// ####### Other Functionality ##########################################
|
||||
// for detecting inheritance from enable_shared_from_this
|
||||
template <class T> inline
|
||||
static auto shared_from_this(T & t) -> decltype(t.shared_from_this());
|
||||
|
||||
// for placement new
|
||||
template <class T, class ... Args> inline
|
||||
static void construct( T *& ptr, Args && ... args )
|
||||
{
|
||||
new (ptr) T( std::forward<Args>( args )... );
|
||||
}
|
||||
|
||||
// for non-placement new with a default constructor
|
||||
template <class T> inline
|
||||
static T * construct()
|
||||
{
|
||||
return new T();
|
||||
}
|
||||
|
||||
template <class T> inline
|
||||
static std::false_type load_and_construct(...)
|
||||
{ return std::false_type(); }
|
||||
|
||||
template<class T, class Archive> inline
|
||||
static auto load_and_construct(Archive & ar, ::cereal::construct<T> & construct) -> decltype(T::load_and_construct(ar, construct))
|
||||
{
|
||||
T::load_and_construct( ar, construct );
|
||||
}
|
||||
}; // end class access
|
||||
|
||||
// ######################################################################
|
||||
//! A specifier used in conjunction with cereal::specialize to disambiguate
|
||||
//! serialization in special cases
|
||||
/*! @relates specialize
|
||||
@ingroup Access */
|
||||
enum class specialization
|
||||
{
|
||||
member_serialize, //!< Force the use of a member serialize function
|
||||
member_load_save, //!< Force the use of a member load/save pair
|
||||
member_load_save_minimal, //!< Force the use of a member minimal load/save pair
|
||||
non_member_serialize, //!< Force the use of a non-member serialize function
|
||||
non_member_load_save, //!< Force the use of a non-member load/save pair
|
||||
non_member_load_save_minimal //!< Force the use of a non-member minimal load/save pair
|
||||
};
|
||||
|
||||
//! A class used to disambiguate cases where cereal cannot detect a unique way of serializing a class
|
||||
/*! cereal attempts to figure out which method of serialization (member vs. non-member serialize
|
||||
or load/save pair) at compile time. If for some reason cereal cannot find a non-ambiguous way
|
||||
of serializing a type, it will produce a static assertion complaining about this.
|
||||
|
||||
This can happen because you have both a serialize and load/save pair, or even because a base
|
||||
class has a serialize (public or private with friend access) and a derived class does not
|
||||
overwrite this due to choosing some other serialization type.
|
||||
|
||||
Specializing this class will tell cereal to explicitly use the serialization type you specify
|
||||
and it will not complain about ambiguity in its compile time selection. However, if cereal detects
|
||||
an ambiguity in specializations, it will continue to issue a static assertion.
|
||||
|
||||
@code{.cpp}
|
||||
class MyParent
|
||||
{
|
||||
friend class cereal::access;
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar ) {}
|
||||
};
|
||||
|
||||
// Although serialize is private in MyParent, to cereal::access it will look public,
|
||||
// even through MyDerived
|
||||
class MyDerived : public MyParent
|
||||
{
|
||||
public:
|
||||
template <class Archive>
|
||||
void load( Archive & ar ) {}
|
||||
|
||||
template <class Archive>
|
||||
void save( Archive & ar ) {}
|
||||
};
|
||||
|
||||
// The load/save pair in MyDerived is ambiguous because serialize in MyParent can
|
||||
// be accessed from cereal::access. This looks the same as making serialize public
|
||||
// in MyParent, making it seem as though MyDerived has both a serialize and a load/save pair.
|
||||
// cereal will complain about this at compile time unless we disambiguate:
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// This struct specialization will tell cereal which is the right way to serialize the ambiguity
|
||||
template <class Archive> struct specialize<Archive, MyDerived, cereal::specialization::member_load_save> {};
|
||||
|
||||
// If we only had a disambiguation for a specific archive type, it would look something like this
|
||||
template <> struct specialize<cereal::BinaryOutputArchive, MyDerived, cereal::specialization::member_load_save> {};
|
||||
}
|
||||
@endcode
|
||||
|
||||
You can also choose to use the macros CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES or
|
||||
CEREAL_SPECIALIZE_FOR_ARCHIVE if you want to type a little bit less.
|
||||
|
||||
@tparam T The type to specialize the serialization for
|
||||
@tparam S The specialization type to use for T
|
||||
@ingroup Access */
|
||||
template <class Archive, class T, specialization S>
|
||||
struct specialize : public std::false_type {};
|
||||
|
||||
//! Convenient macro for performing specialization for all archive types
|
||||
/*! This performs specialization for the specific type for all types of archives.
|
||||
This macro should be placed at the global namespace.
|
||||
|
||||
@code{cpp}
|
||||
struct MyType {};
|
||||
CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( MyType, cereal::specialization::member_load_save );
|
||||
@endcode
|
||||
|
||||
@relates specialize
|
||||
@ingroup Access */
|
||||
#define CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( Type, Specialization ) \
|
||||
namespace cereal { template <class Archive> struct specialize<Archive, Type, Specialization> {}; }
|
||||
|
||||
//! Convenient macro for performing specialization for a single archive type
|
||||
/*! This performs specialization for the specific type for a single type of archive.
|
||||
This macro should be placed at the global namespace.
|
||||
|
||||
@code{cpp}
|
||||
struct MyType {};
|
||||
CEREAL_SPECIALIZE_FOR_ARCHIVE( cereal::XMLInputArchive, MyType, cereal::specialization::member_load_save );
|
||||
@endcode
|
||||
|
||||
@relates specialize
|
||||
@ingroup Access */
|
||||
#define CEREAL_SPECIALIZE_FOR_ARCHIVE( Archive, Type, Specialization ) \
|
||||
namespace cereal { template <> struct specialize<Archive, Type, Specialization> {}; }
|
||||
|
||||
// ######################################################################
|
||||
// Deferred Implementation, see construct for more information
|
||||
template <class T> template <class ... Args> inline
|
||||
void construct<T>::operator()( Args && ... args )
|
||||
{
|
||||
if( itsValid )
|
||||
throw Exception("Attempting to construct an already initialized object");
|
||||
|
||||
::cereal::access::construct( itsPtr, std::forward<Args>( args )... );
|
||||
itsValid = true;
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_ACCESS_HPP_
|
||||
163
libs/cereal/cereal/archives/adapters.hpp
Normal file
163
libs/cereal/cereal/archives/adapters.hpp
Normal file
@ -0,0 +1,163 @@
|
||||
/*! \file adapters.hpp
|
||||
\brief Archive adapters that provide additional functionality
|
||||
on top of an existing archive */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_ARCHIVES_ADAPTERS_HPP_
|
||||
#define CEREAL_ARCHIVES_ADAPTERS_HPP_
|
||||
|
||||
#include <cereal/details/helpers.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
#ifdef CEREAL_FUTURE_EXPERIMENTAL
|
||||
|
||||
// Forward declaration for friend access
|
||||
template <class U, class A> U & get_user_data( A & );
|
||||
|
||||
//! Wraps an archive and gives access to user data
|
||||
/*! This adapter is useful if you require access to
|
||||
either raw pointers or references within your
|
||||
serialization functions.
|
||||
|
||||
While cereal does not directly support serialization
|
||||
raw pointers or references, it is sometimes the case
|
||||
that you may want to supply something such as a raw
|
||||
pointer or global reference to some constructor.
|
||||
In this situation this adapter would likely be used
|
||||
with the construct class to allow for non-default
|
||||
constructors.
|
||||
|
||||
@note This feature is experimental and may be altered or removed in a future release. See issue #46.
|
||||
|
||||
@code{.cpp}
|
||||
struct MyUserData
|
||||
{
|
||||
int * myRawPointer;
|
||||
std::reference_wrapper<MyOtherType> myReference;
|
||||
};
|
||||
|
||||
struct MyClass
|
||||
{
|
||||
// Note the raw pointer parameter
|
||||
MyClass( int xx, int * rawP );
|
||||
|
||||
int x;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{ ar( x ); }
|
||||
|
||||
template <class Archive>
|
||||
static void load_and_construct( Archive & ar, cereal::construct<MyClass> & construct )
|
||||
{
|
||||
int xx;
|
||||
ar( xx );
|
||||
// note the need to use get_user_data to retrieve user data from the archive
|
||||
construct( xx, cereal::get_user_data<MyUserData>( ar ).myRawPointer );
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
MyUserData md;
|
||||
md.myRawPointer = &something;
|
||||
md.myReference = someInstanceOfType;
|
||||
|
||||
std::ifstream is( "data.xml" );
|
||||
cereal::UserDataAdapter<MyUserData, cereal::XMLInputArchive> ar( md, is );
|
||||
|
||||
std::unique_ptr<MyClass> sc;
|
||||
ar( sc ); // use as normal
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@relates get_user_data
|
||||
|
||||
@tparam UserData The type to give the archive access to
|
||||
@tparam Archive The archive to wrap */
|
||||
template <class UserData, class Archive>
|
||||
class UserDataAdapter : public Archive
|
||||
{
|
||||
public:
|
||||
//! Construct the archive with some user data struct
|
||||
/*! This will forward all arguments (other than the user
|
||||
data) to the wrapped archive type. The UserDataAdapter
|
||||
can then be used identically to the wrapped archive type
|
||||
|
||||
@tparam Args The arguments to pass to the constructor of
|
||||
the archive. */
|
||||
template <class ... Args>
|
||||
UserDataAdapter( UserData & ud, Args && ... args ) :
|
||||
Archive( std::forward<Args>( args )... ),
|
||||
userdata( ud )
|
||||
{ }
|
||||
|
||||
private:
|
||||
//! Overload the rtti function to enable dynamic_cast
|
||||
void rtti() {}
|
||||
friend UserData & get_user_data<UserData>( Archive & ar );
|
||||
UserData & userdata; //!< The actual user data
|
||||
};
|
||||
|
||||
//! Retrieves user data from an archive wrapped by UserDataAdapter
|
||||
/*! This will attempt to retrieve the user data associated with
|
||||
some archive wrapped by UserDataAdapter. If this is used on
|
||||
an archive that is not wrapped, a run-time exception will occur.
|
||||
|
||||
@note This feature is experimental and may be altered or removed in a future release. See issue #46.
|
||||
|
||||
@note The correct use of this function cannot be enforced at compile
|
||||
time.
|
||||
|
||||
@relates UserDataAdapter
|
||||
@tparam UserData The data struct contained in the archive
|
||||
@tparam Archive The archive, which should be wrapped by UserDataAdapter
|
||||
@param ar The archive
|
||||
@throws Exception if the archive this is used upon is not wrapped with
|
||||
UserDataAdapter. */
|
||||
template <class UserData, class Archive>
|
||||
UserData & get_user_data( Archive & ar )
|
||||
{
|
||||
try
|
||||
{
|
||||
return dynamic_cast<UserDataAdapter<UserData, Archive> &>( ar ).userdata;
|
||||
}
|
||||
catch( std::bad_cast const & )
|
||||
{
|
||||
throw ::cereal::Exception("Attempting to get user data from archive not wrapped in UserDataAdapter");
|
||||
}
|
||||
}
|
||||
#endif // CEREAL_FUTURE_EXPERIMENTAL
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_ARCHIVES_ADAPTERS_HPP_
|
||||
165
libs/cereal/cereal/archives/binary.hpp
Normal file
165
libs/cereal/cereal/archives/binary.hpp
Normal file
@ -0,0 +1,165 @@
|
||||
/*! \file binary.hpp
|
||||
\brief Binary input and output archives */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_ARCHIVES_BINARY_HPP_
|
||||
#define CEREAL_ARCHIVES_BINARY_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <sstream>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// ######################################################################
|
||||
//! An output archive designed to save data in a compact binary representation
|
||||
/*! This archive outputs data to a stream in an extremely compact binary
|
||||
representation with as little extra metadata as possible.
|
||||
|
||||
This archive does nothing to ensure that the endianness of the saved
|
||||
and loaded data is the same. If you need to have portability over
|
||||
architectures with different endianness, use PortableBinaryOutputArchive.
|
||||
|
||||
When using a binary archive and a file stream, you must use the
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
inadvertently.
|
||||
|
||||
\ingroup Archives */
|
||||
class BinaryOutputArchive : public OutputArchive<BinaryOutputArchive, AllowEmptyClassElision>
|
||||
{
|
||||
public:
|
||||
//! Construct, outputting to the provided stream
|
||||
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
|
||||
even cout! */
|
||||
BinaryOutputArchive(std::ostream & stream) :
|
||||
OutputArchive<BinaryOutputArchive, AllowEmptyClassElision>(this),
|
||||
itsStream(stream)
|
||||
{ }
|
||||
|
||||
//! Writes size bytes of data to the output stream
|
||||
void saveBinary( const void * data, std::size_t size )
|
||||
{
|
||||
auto const writtenSize = static_cast<std::size_t>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size ) );
|
||||
|
||||
if(writtenSize != size)
|
||||
throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream & itsStream;
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
//! An input archive designed to load data saved using BinaryOutputArchive
|
||||
/* This archive does nothing to ensure that the endianness of the saved
|
||||
and loaded data is the same. If you need to have portability over
|
||||
architectures with different endianness, use PortableBinaryOutputArchive.
|
||||
|
||||
When using a binary archive and a file stream, you must use the
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
inadvertently.
|
||||
|
||||
\ingroup Archives */
|
||||
class BinaryInputArchive : public InputArchive<BinaryInputArchive, AllowEmptyClassElision>
|
||||
{
|
||||
public:
|
||||
//! Construct, loading from the provided stream
|
||||
BinaryInputArchive(std::istream & stream) :
|
||||
InputArchive<BinaryInputArchive, AllowEmptyClassElision>(this),
|
||||
itsStream(stream)
|
||||
{ }
|
||||
|
||||
//! Reads size bytes of data from the input stream
|
||||
void loadBinary( void * const data, std::size_t size )
|
||||
{
|
||||
auto const readSize = static_cast<std::size_t>( itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size ) );
|
||||
|
||||
if(readSize != size)
|
||||
throw Exception("Failed to read " + std::to_string(size) + " bytes from input stream! Read " + std::to_string(readSize));
|
||||
}
|
||||
|
||||
private:
|
||||
std::istream & itsStream;
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
// Common BinaryArchive serialization functions
|
||||
|
||||
//! Saving for POD types to binary
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME(BinaryOutputArchive & ar, T const & t)
|
||||
{
|
||||
ar.saveBinary(std::addressof(t), sizeof(t));
|
||||
}
|
||||
|
||||
//! Loading for POD types from binary
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME(BinaryInputArchive & ar, T & t)
|
||||
{
|
||||
ar.loadBinary(std::addressof(t), sizeof(t));
|
||||
}
|
||||
|
||||
//! Serializing NVP types to binary
|
||||
template <class Archive, class T> inline
|
||||
CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, NameValuePair<T> & t )
|
||||
{
|
||||
ar( t.value );
|
||||
}
|
||||
|
||||
//! Serializing SizeTags to binary
|
||||
template <class Archive, class T> inline
|
||||
CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, SizeTag<T> & t )
|
||||
{
|
||||
ar( t.size );
|
||||
}
|
||||
|
||||
//! Saving binary data
|
||||
template <class T> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME(BinaryOutputArchive & ar, BinaryData<T> const & bd)
|
||||
{
|
||||
ar.saveBinary( bd.data, static_cast<std::size_t>( bd.size ) );
|
||||
}
|
||||
|
||||
//! Loading binary data
|
||||
template <class T> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME(BinaryInputArchive & ar, BinaryData<T> & bd)
|
||||
{
|
||||
ar.loadBinary(bd.data, static_cast<std::size_t>(bd.size));
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
// register archives for polymorphic support
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::BinaryOutputArchive)
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::BinaryInputArchive)
|
||||
|
||||
// tie input and output archives together
|
||||
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::BinaryInputArchive, cereal::BinaryOutputArchive)
|
||||
|
||||
#endif // CEREAL_ARCHIVES_BINARY_HPP_
|
||||
912
libs/cereal/cereal/archives/json.hpp
Normal file
912
libs/cereal/cereal/archives/json.hpp
Normal file
@ -0,0 +1,912 @@
|
||||
/*! \file json.hpp
|
||||
\brief JSON input and output archives */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_ARCHIVES_JSON_HPP_
|
||||
#define CEREAL_ARCHIVES_JSON_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/details/util.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! An exception thrown when rapidjson fails an internal assertion
|
||||
/*! @ingroup Utility */
|
||||
struct RapidJSONException : Exception
|
||||
{ RapidJSONException( const char * what_ ) : Exception( what_ ) {} };
|
||||
}
|
||||
|
||||
// Override rapidjson assertions to throw exceptions by default
|
||||
#ifndef RAPIDJSON_ASSERT
|
||||
#define RAPIDJSON_ASSERT(x) if(!(x)){ \
|
||||
throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); }
|
||||
#endif // RAPIDJSON_ASSERT
|
||||
|
||||
#include <cereal/external/rapidjson/prettywriter.h>
|
||||
#include <cereal/external/rapidjson/genericstream.h>
|
||||
#include <cereal/external/rapidjson/reader.h>
|
||||
#include <cereal/external/rapidjson/document.h>
|
||||
#include <cereal/external/base64.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// ######################################################################
|
||||
//! An output archive designed to save data to JSON
|
||||
/*! This archive uses RapidJSON to build serialie data to JSON.
|
||||
|
||||
JSON archives provides a human readable output but at decreased
|
||||
performance (both in time and space) compared to binary archives.
|
||||
|
||||
JSON benefits greatly from name-value pairs, which if present, will
|
||||
name the nodes in the output. If these are not present, each level
|
||||
of the output will be given an automatically generated delimited name.
|
||||
|
||||
The precision of the output archive controls the number of decimals output
|
||||
for floating point numbers and should be sufficiently large (i.e. at least 20)
|
||||
if there is a desire to have binary equality between the numbers output and
|
||||
those read in. In general you should expect a loss of precision when going
|
||||
from floating point to text and back.
|
||||
|
||||
JSON archives do not output the size information for any dynamically sized structure
|
||||
and instead infer it from the number of children for a node. This means that data
|
||||
can be hand edited for dynamic sized structures and will still be readable. This
|
||||
is accomplished through the cereal::SizeTag object, which will cause the archive
|
||||
to output the data as a JSON array (e.g. marked by [] instead of {}), which indicates
|
||||
that the container is variable sized and may be edited.
|
||||
|
||||
\ingroup Archives */
|
||||
class JSONOutputArchive : public OutputArchive<JSONOutputArchive>, public traits::TextArchive
|
||||
{
|
||||
enum class NodeType { StartObject, InObject, StartArray, InArray };
|
||||
|
||||
typedef rapidjson::GenericWriteStream WriteStream;
|
||||
typedef rapidjson::PrettyWriter<WriteStream> JSONWriter;
|
||||
|
||||
public:
|
||||
/*! @name Common Functionality
|
||||
Common use cases for directly interacting with an JSONOutputArchive */
|
||||
//! @{
|
||||
|
||||
//! A class containing various advanced options for the JSON archive
|
||||
class Options
|
||||
{
|
||||
public:
|
||||
//! Default options
|
||||
static Options Default(){ return Options(); }
|
||||
|
||||
//! Default options with no indentation
|
||||
static Options NoIndent(){ return Options( std::numeric_limits<double>::max_digits10, IndentChar::space, 0 ); }
|
||||
|
||||
//! The character to use for indenting
|
||||
enum class IndentChar : char
|
||||
{
|
||||
space = ' ',
|
||||
tab = '\t',
|
||||
newline = '\n',
|
||||
carriage_return = '\r'
|
||||
};
|
||||
|
||||
//! Specify specific options for the JSONOutputArchive
|
||||
/*! @param precision The precision used for floating point numbers
|
||||
@param indentChar The type of character to indent with
|
||||
@param indentLength The number of indentChar to use for indentation
|
||||
(0 corresponds to no indentation) */
|
||||
explicit Options( int precision = std::numeric_limits<double>::max_digits10,
|
||||
IndentChar indentChar = IndentChar::space,
|
||||
unsigned int indentLength = 4 ) :
|
||||
itsPrecision( precision ),
|
||||
itsIndentChar( static_cast<char>(indentChar) ),
|
||||
itsIndentLength( indentLength ) { }
|
||||
|
||||
private:
|
||||
friend class JSONOutputArchive;
|
||||
int itsPrecision;
|
||||
char itsIndentChar;
|
||||
unsigned int itsIndentLength;
|
||||
};
|
||||
|
||||
//! Construct, outputting to the provided stream
|
||||
/*! @param stream The stream to output to.
|
||||
@param options The JSON specific options to use. See the Options struct
|
||||
for the values of default parameters */
|
||||
JSONOutputArchive(std::ostream & stream, Options const & options = Options::Default() ) :
|
||||
OutputArchive<JSONOutputArchive>(this),
|
||||
itsWriteStream(stream),
|
||||
itsWriter(itsWriteStream, options.itsPrecision),
|
||||
itsNextName(nullptr)
|
||||
{
|
||||
itsWriter.SetIndent( options.itsIndentChar, options.itsIndentLength );
|
||||
itsNameCounter.push(0);
|
||||
itsNodeStack.push(NodeType::StartObject);
|
||||
}
|
||||
|
||||
//! Destructor, flushes the JSON
|
||||
~JSONOutputArchive()
|
||||
{
|
||||
if (itsNodeStack.top() == NodeType::InObject)
|
||||
itsWriter.EndObject();
|
||||
}
|
||||
|
||||
//! Saves some binary data, encoded as a base64 string, with an optional name
|
||||
/*! This will create a new node, optionally named, and insert a value that consists of
|
||||
the data encoded as a base64 string */
|
||||
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
|
||||
{
|
||||
setNextName( name );
|
||||
writeName();
|
||||
|
||||
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
|
||||
saveValue( base64string );
|
||||
};
|
||||
|
||||
//! @}
|
||||
/*! @name Internal Functionality
|
||||
Functionality designed for use by those requiring control over the inner mechanisms of
|
||||
the JSONOutputArchive */
|
||||
//! @{
|
||||
|
||||
//! Starts a new node in the JSON output
|
||||
/*! The node can optionally be given a name by calling setNextName prior
|
||||
to creating the node
|
||||
|
||||
Nodes only need to be started for types that are themselves objects or arrays */
|
||||
void startNode()
|
||||
{
|
||||
writeName();
|
||||
itsNodeStack.push(NodeType::StartObject);
|
||||
itsNameCounter.push(0);
|
||||
}
|
||||
|
||||
//! Designates the most recently added node as finished
|
||||
void finishNode()
|
||||
{
|
||||
// if we ended up serializing an empty object or array, writeName
|
||||
// will never have been called - so start and then immediately end
|
||||
// the object/array.
|
||||
//
|
||||
// We'll also end any object/arrays we happen to be in
|
||||
switch(itsNodeStack.top())
|
||||
{
|
||||
case NodeType::StartArray:
|
||||
itsWriter.StartArray();
|
||||
case NodeType::InArray:
|
||||
itsWriter.EndArray();
|
||||
break;
|
||||
case NodeType::StartObject:
|
||||
itsWriter.StartObject();
|
||||
case NodeType::InObject:
|
||||
itsWriter.EndObject();
|
||||
break;
|
||||
}
|
||||
|
||||
itsNodeStack.pop();
|
||||
itsNameCounter.pop();
|
||||
}
|
||||
|
||||
//! Sets the name for the next node created with startNode
|
||||
void setNextName( const char * name )
|
||||
{
|
||||
itsNextName = name;
|
||||
}
|
||||
|
||||
//! Saves a bool to the current node
|
||||
void saveValue(bool b) { itsWriter.Bool_(b); }
|
||||
//! Saves an int to the current node
|
||||
void saveValue(int i) { itsWriter.Int(i); }
|
||||
//! Saves a uint to the current node
|
||||
void saveValue(unsigned u) { itsWriter.Uint(u); }
|
||||
//! Saves an int64 to the current node
|
||||
void saveValue(int64_t i64) { itsWriter.Int64(i64); }
|
||||
//! Saves a uint64 to the current node
|
||||
void saveValue(uint64_t u64) { itsWriter.Uint64(u64); }
|
||||
//! Saves a double to the current node
|
||||
void saveValue(double d) { itsWriter.Double(d); }
|
||||
//! Saves a string to the current node
|
||||
void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast<rapidjson::SizeType>( s.size() )); }
|
||||
//! Saves a const char * to the current node
|
||||
void saveValue(char const * s) { itsWriter.String(s); }
|
||||
|
||||
private:
|
||||
// Some compilers/OS have difficulty disambiguating the above for various flavors of longs, so we provide
|
||||
// special overloads to handle these cases.
|
||||
|
||||
//! 32 bit signed long saving to current node
|
||||
template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
|
||||
std::is_signed<T>::value> = traits::sfinae> inline
|
||||
void saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
|
||||
|
||||
//! non 32 bit signed long saving to current node
|
||||
template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
|
||||
std::is_signed<T>::value> = traits::sfinae> inline
|
||||
void saveLong(T l){ saveValue( static_cast<std::int64_t>( l ) ); }
|
||||
|
||||
//! 32 bit unsigned long saving to current node
|
||||
template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
|
||||
std::is_unsigned<T>::value> = traits::sfinae> inline
|
||||
void saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
|
||||
|
||||
//! non 32 bit unsigned long saving to current node
|
||||
template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
|
||||
std::is_unsigned<T>::value> = traits::sfinae> inline
|
||||
void saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
|
||||
|
||||
public:
|
||||
#ifdef _MSC_VER
|
||||
//! MSVC only long overload to current node
|
||||
void saveValue( unsigned long lu ){ saveLong( lu ); };
|
||||
#else // _MSC_VER
|
||||
//! Serialize a long if it would not be caught otherwise
|
||||
template <class T, traits::EnableIf<std::is_same<T, long>::value,
|
||||
!std::is_same<T, std::int32_t>::value,
|
||||
!std::is_same<T, std::int64_t>::value> = traits::sfinae> inline
|
||||
void saveValue( T t ){ saveLong( t ); }
|
||||
|
||||
//! Serialize an unsigned long if it would not be caught otherwise
|
||||
template <class T, traits::EnableIf<std::is_same<T, unsigned long>::value,
|
||||
!std::is_same<T, std::uint32_t>::value,
|
||||
!std::is_same<T, std::uint64_t>::value> = traits::sfinae> inline
|
||||
void saveValue( T t ){ saveLong( t ); }
|
||||
#endif // _MSC_VER
|
||||
|
||||
//! Save exotic arithmetic as strings to current node
|
||||
/*! Handles long long (if distinct from other types), unsigned long (if distinct), and long double */
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
|
||||
!std::is_same<T, long>::value,
|
||||
!std::is_same<T, unsigned long>::value,
|
||||
!std::is_same<T, std::int64_t>::value,
|
||||
!std::is_same<T, std::uint64_t>::value,
|
||||
(sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long))> = traits::sfinae> inline
|
||||
void saveValue(T const & t)
|
||||
{
|
||||
std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
|
||||
ss << t;
|
||||
saveValue( ss.str() );
|
||||
}
|
||||
|
||||
//! Write the name of the upcoming node and prepare object/array state
|
||||
/*! Since writeName is called for every value that is output, regardless of
|
||||
whether it has a name or not, it is the place where we will do a deferred
|
||||
check of our node state and decide whether we are in an array or an object.
|
||||
|
||||
The general workflow of saving to the JSON archive is:
|
||||
|
||||
1. (optional) Set the name for the next node to be created, usually done by an NVP
|
||||
2. Start the node
|
||||
3. (if there is data to save) Write the name of the node (this function)
|
||||
4. (if there is data to save) Save the data (with saveValue)
|
||||
5. Finish the node
|
||||
*/
|
||||
void writeName()
|
||||
{
|
||||
NodeType const & nodeType = itsNodeStack.top();
|
||||
|
||||
// Start up either an object or an array, depending on state
|
||||
if(nodeType == NodeType::StartArray)
|
||||
{
|
||||
itsWriter.StartArray();
|
||||
itsNodeStack.top() = NodeType::InArray;
|
||||
}
|
||||
else if(nodeType == NodeType::StartObject)
|
||||
{
|
||||
itsNodeStack.top() = NodeType::InObject;
|
||||
itsWriter.StartObject();
|
||||
}
|
||||
|
||||
// Array types do not output names
|
||||
if(nodeType == NodeType::InArray) return;
|
||||
|
||||
if(itsNextName == nullptr)
|
||||
{
|
||||
std::string name = "value" + std::to_string( itsNameCounter.top()++ ) + "\0";
|
||||
saveValue(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
saveValue(itsNextName);
|
||||
itsNextName = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//! Designates that the current node should be output as an array, not an object
|
||||
void makeArray()
|
||||
{
|
||||
itsNodeStack.top() = NodeType::StartArray;
|
||||
}
|
||||
|
||||
//! @}
|
||||
|
||||
private:
|
||||
WriteStream itsWriteStream; //!< Rapidjson write stream
|
||||
JSONWriter itsWriter; //!< Rapidjson writer
|
||||
char const * itsNextName; //!< The next name
|
||||
std::stack<uint32_t> itsNameCounter; //!< Counter for creating unique names for unnamed nodes
|
||||
std::stack<NodeType> itsNodeStack;
|
||||
}; // JSONOutputArchive
|
||||
|
||||
// ######################################################################
|
||||
//! An input archive designed to load data from JSON
|
||||
/*! This archive uses RapidJSON to read in a JSON archive.
|
||||
|
||||
Input JSON should have been produced by the JSONOutputArchive. Data can
|
||||
only be added to dynamically sized containers (marked by JSON arrays) -
|
||||
the input archive will determine their size by looking at the number of child nodes.
|
||||
Only JSON originating from a JSONOutputArchive is officially supported, but data
|
||||
from other sources may work if properly formatted.
|
||||
|
||||
The JSONInputArchive does not require that nodes are loaded in the same
|
||||
order they were saved by JSONOutputArchive. Using name value pairs (NVPs),
|
||||
it is possible to load in an out of order fashion or otherwise skip/select
|
||||
specific nodes to load.
|
||||
|
||||
The default behavior of the input archive is to read sequentially starting
|
||||
with the first node and exploring its children. When a given NVP does
|
||||
not match the read in name for a node, the archive will search for that
|
||||
node at the current level and load it if it exists. After loading an out of
|
||||
order node, the archive will then proceed back to loading sequentially from
|
||||
its new position.
|
||||
|
||||
Consider this simple example where loading of some data is skipped:
|
||||
|
||||
@code{cpp}
|
||||
// imagine the input file has someData(1-9) saved in order at the top level node
|
||||
ar( someData1, someData2, someData3 ); // XML loads in the order it sees in the file
|
||||
ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
|
||||
// match expected NVP name, so we search
|
||||
// for the given NVP and load that value
|
||||
ar( someData7, someData8, someData9 ); // with no NVP given, loading resumes at its
|
||||
// current location, proceeding sequentially
|
||||
@endcode
|
||||
|
||||
\ingroup Archives */
|
||||
class JSONInputArchive : public InputArchive<JSONInputArchive>, public traits::TextArchive
|
||||
{
|
||||
private:
|
||||
typedef rapidjson::GenericReadStream ReadStream;
|
||||
typedef rapidjson::GenericValue<rapidjson::UTF8<>> JSONValue;
|
||||
typedef JSONValue::ConstMemberIterator MemberIterator;
|
||||
typedef JSONValue::ConstValueIterator ValueIterator;
|
||||
typedef rapidjson::Document::GenericValue GenericValue;
|
||||
|
||||
public:
|
||||
/*! @name Common Functionality
|
||||
Common use cases for directly interacting with an JSONInputArchive */
|
||||
//! @{
|
||||
|
||||
//! Construct, reading from the provided stream
|
||||
/*! @param stream The stream to read from */
|
||||
JSONInputArchive(std::istream & stream) :
|
||||
InputArchive<JSONInputArchive>(this),
|
||||
itsNextName( nullptr ),
|
||||
itsReadStream(stream)
|
||||
{
|
||||
itsDocument.ParseStream<0>(itsReadStream);
|
||||
itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
|
||||
}
|
||||
|
||||
//! Loads some binary data, encoded as a base64 string
|
||||
/*! This will automatically start and finish a node to load the data, and can be called directly by
|
||||
users.
|
||||
|
||||
Note that this follows the same ordering rules specified in the class description in regards
|
||||
to loading in/out of order */
|
||||
void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
|
||||
{
|
||||
itsNextName = name;
|
||||
|
||||
std::string encoded;
|
||||
loadValue( encoded );
|
||||
auto decoded = base64::decode( encoded );
|
||||
|
||||
if( size != decoded.size() )
|
||||
throw Exception("Decoded binary data size does not match specified size");
|
||||
|
||||
std::memcpy( data, decoded.data(), decoded.size() );
|
||||
itsNextName = nullptr;
|
||||
};
|
||||
|
||||
private:
|
||||
//! @}
|
||||
/*! @name Internal Functionality
|
||||
Functionality designed for use by those requiring control over the inner mechanisms of
|
||||
the JSONInputArchive */
|
||||
//! @{
|
||||
|
||||
//! An internal iterator that handles both array and object types
|
||||
/*! This class is a variant and holds both types of iterators that
|
||||
rapidJSON supports - one for arrays and one for objects. */
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator() : itsIndex( 0 ), itsType(Null_) {}
|
||||
|
||||
Iterator(MemberIterator begin, MemberIterator end) :
|
||||
itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsType(Member)
|
||||
{ }
|
||||
|
||||
Iterator(ValueIterator begin, ValueIterator end) :
|
||||
itsValueItBegin(begin), itsValueItEnd(end), itsIndex(0), itsType(Value)
|
||||
{ }
|
||||
|
||||
//! Advance to the next node
|
||||
Iterator & operator++()
|
||||
{
|
||||
++itsIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Get the value of the current node
|
||||
GenericValue const & value()
|
||||
{
|
||||
switch(itsType)
|
||||
{
|
||||
case Value : return itsValueItBegin[itsIndex];
|
||||
case Member: return itsMemberItBegin[itsIndex].value;
|
||||
default: throw cereal::Exception("Invalid Iterator Type!");
|
||||
}
|
||||
}
|
||||
|
||||
//! Get the name of the current node, or nullptr if it has no name
|
||||
const char * name() const
|
||||
{
|
||||
if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
|
||||
return itsMemberItBegin[itsIndex].name.GetString();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//! Adjust our position such that we are at the node with the given name
|
||||
/*! @throws Exception if no such named node exists */
|
||||
inline void search( const char * searchName )
|
||||
{
|
||||
const auto len = std::strlen( searchName );
|
||||
size_t index = 0;
|
||||
for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
|
||||
{
|
||||
const auto currentName = it->name.GetString();
|
||||
if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
|
||||
( std::strlen( currentName ) == len ) )
|
||||
{
|
||||
itsIndex = index;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception("JSON Parsing failed - provided NVP not found");
|
||||
}
|
||||
|
||||
private:
|
||||
MemberIterator itsMemberItBegin, itsMemberItEnd; //!< The member iterator (object)
|
||||
ValueIterator itsValueItBegin, itsValueItEnd; //!< The value iterator (array)
|
||||
size_t itsIndex; //!< The current index of this iterator
|
||||
enum Type {Value, Member, Null_} itsType; //!< Whether this holds values (array) or members (objects) or nothing
|
||||
};
|
||||
|
||||
//! Searches for the expectedName node if it doesn't match the actualName
|
||||
/*! This needs to be called before every load or node start occurs. This function will
|
||||
check to see if an NVP has been provided (with setNextName) and if so, see if that name matches the actual
|
||||
next name given. If the names do not match, it will search in the current level of the JSON for that name.
|
||||
If the name is not found, an exception will be thrown.
|
||||
|
||||
Resets the NVP name after called.
|
||||
|
||||
@throws Exception if an expectedName is given and not found */
|
||||
inline void search()
|
||||
{
|
||||
// The name an NVP provided with setNextName()
|
||||
if( itsNextName )
|
||||
{
|
||||
// The actual name of the current node
|
||||
auto const actualName = itsIteratorStack.back().name();
|
||||
|
||||
// Do a search if we don't see a name coming up, or if the names don't match
|
||||
if( !actualName || std::strcmp( itsNextName, actualName ) != 0 )
|
||||
itsIteratorStack.back().search( itsNextName );
|
||||
}
|
||||
|
||||
itsNextName = nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
//! Starts a new node, going into its proper iterator
|
||||
/*! This places an iterator for the next node to be parsed onto the iterator stack. If the next
|
||||
node is an array, this will be a value iterator, otherwise it will be a member iterator.
|
||||
|
||||
By default our strategy is to start with the document root node and then recursively iterate through
|
||||
all children in the order they show up in the document.
|
||||
We don't need to know NVPs to do this; we'll just blindly load in the order things appear in.
|
||||
|
||||
If we were given an NVP, we will search for it if it does not match our the name of the next node
|
||||
that would normally be loaded. This functionality is provided by search(). */
|
||||
void startNode()
|
||||
{
|
||||
search();
|
||||
|
||||
if(itsIteratorStack.back().value().IsArray())
|
||||
itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
|
||||
else
|
||||
itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
|
||||
}
|
||||
|
||||
//! Finishes the most recently started node
|
||||
void finishNode()
|
||||
{
|
||||
itsIteratorStack.pop_back();
|
||||
++itsIteratorStack.back();
|
||||
}
|
||||
|
||||
//! Retrieves the current node name
|
||||
/*! @return nullptr if no name exists */
|
||||
const char * getNodeName() const
|
||||
{
|
||||
return itsIteratorStack.back().name();
|
||||
}
|
||||
|
||||
//! Sets the name for the next node created with startNode
|
||||
void setNextName( const char * name )
|
||||
{
|
||||
itsNextName = name;
|
||||
}
|
||||
|
||||
//! Loads a value from the current node - small signed overload
|
||||
template <class T, traits::EnableIf<std::is_signed<T>::value,
|
||||
sizeof(T) < sizeof(int64_t)> = traits::sfinae> inline
|
||||
void loadValue(T & val)
|
||||
{
|
||||
search();
|
||||
|
||||
val = static_cast<T>( itsIteratorStack.back().value().GetInt() );
|
||||
++itsIteratorStack.back();
|
||||
}
|
||||
|
||||
//! Loads a value from the current node - small unsigned overload
|
||||
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
|
||||
sizeof(T) < sizeof(uint64_t),
|
||||
!std::is_same<bool, T>::value> = traits::sfinae> inline
|
||||
void loadValue(T & val)
|
||||
{
|
||||
search();
|
||||
|
||||
val = static_cast<T>( itsIteratorStack.back().value().GetUint() );
|
||||
++itsIteratorStack.back();
|
||||
}
|
||||
|
||||
//! Loads a value from the current node - bool overload
|
||||
void loadValue(bool & val) { search(); val = itsIteratorStack.back().value().GetBool_(); ++itsIteratorStack.back(); }
|
||||
//! Loads a value from the current node - int64 overload
|
||||
void loadValue(int64_t & val) { search(); val = itsIteratorStack.back().value().GetInt64(); ++itsIteratorStack.back(); }
|
||||
//! Loads a value from the current node - uint64 overload
|
||||
void loadValue(uint64_t & val) { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
|
||||
//! Loads a value from the current node - float overload
|
||||
void loadValue(float & val) { search(); val = static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
|
||||
//! Loads a value from the current node - double overload
|
||||
void loadValue(double & val) { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
|
||||
//! Loads a value from the current node - string overload
|
||||
void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
|
||||
|
||||
// Special cases to handle various flavors of long, which tend to conflict with
|
||||
// the int32_t or int64_t on various compiler/OS combinations. MSVC doesn't need any of this.
|
||||
#ifndef _MSC_VER
|
||||
private:
|
||||
//! 32 bit signed long loading from current node
|
||||
template <class T> inline
|
||||
typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value, void>::type
|
||||
loadLong(T & l){ loadValue( reinterpret_cast<std::int32_t&>( l ) ); }
|
||||
|
||||
//! non 32 bit signed long loading from current node
|
||||
template <class T> inline
|
||||
typename std::enable_if<sizeof(T) == sizeof(std::int64_t) && std::is_signed<T>::value, void>::type
|
||||
loadLong(T & l){ loadValue( reinterpret_cast<std::int64_t&>( l ) ); }
|
||||
|
||||
//! 32 bit unsigned long loading from current node
|
||||
template <class T> inline
|
||||
typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value, void>::type
|
||||
loadLong(T & lu){ loadValue( reinterpret_cast<std::uint32_t&>( lu ) ); }
|
||||
|
||||
//! non 32 bit unsigned long loading from current node
|
||||
template <class T> inline
|
||||
typename std::enable_if<sizeof(T) == sizeof(std::uint64_t) && !std::is_signed<T>::value, void>::type
|
||||
loadLong(T & lu){ loadValue( reinterpret_cast<std::uint64_t&>( lu ) ); }
|
||||
|
||||
public:
|
||||
//! Serialize a long if it would not be caught otherwise
|
||||
template <class T> inline
|
||||
typename std::enable_if<std::is_same<T, long>::value &&
|
||||
!std::is_same<T, std::int32_t>::value &&
|
||||
!std::is_same<T, std::int64_t>::value, void>::type
|
||||
loadValue( T & t ){ loadLong(t); }
|
||||
|
||||
//! Serialize an unsigned long if it would not be caught otherwise
|
||||
template <class T> inline
|
||||
typename std::enable_if<std::is_same<T, unsigned long>::value &&
|
||||
!std::is_same<T, std::uint32_t>::value &&
|
||||
!std::is_same<T, std::uint64_t>::value, void>::type
|
||||
loadValue( T & t ){ loadLong(t); }
|
||||
#endif // _MSC_VER
|
||||
|
||||
private:
|
||||
//! Convert a string to a long long
|
||||
void stringToNumber( std::string const & str, long long & val ) { val = std::stoll( str ); }
|
||||
//! Convert a string to an unsigned long long
|
||||
void stringToNumber( std::string const & str, unsigned long long & val ) { val = std::stoull( str ); }
|
||||
//! Convert a string to a long double
|
||||
void stringToNumber( std::string const & str, long double & val ) { val = std::stold( str ); }
|
||||
|
||||
public:
|
||||
//! Loads a value from the current node - long double and long long overloads
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
|
||||
!std::is_same<T, long>::value,
|
||||
!std::is_same<T, unsigned long>::value,
|
||||
!std::is_same<T, std::int64_t>::value,
|
||||
!std::is_same<T, std::uint64_t>::value,
|
||||
(sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long))> = traits::sfinae>
|
||||
inline void loadValue(T & val)
|
||||
{
|
||||
std::string encoded;
|
||||
loadValue( encoded );
|
||||
stringToNumber( encoded, val );
|
||||
}
|
||||
|
||||
//! Loads the size for a SizeTag
|
||||
void loadSize(size_type & size)
|
||||
{
|
||||
size = (itsIteratorStack.rbegin() + 1)->value().Size();
|
||||
}
|
||||
|
||||
//! @}
|
||||
|
||||
private:
|
||||
const char * itsNextName; //!< Next name set by NVP
|
||||
ReadStream itsReadStream; //!< Rapidjson write stream
|
||||
std::vector<Iterator> itsIteratorStack; //!< 'Stack' of rapidJSON iterators
|
||||
rapidjson::Document itsDocument; //!< Rapidjson document
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
// JSONArchive prologue and epilogue functions
|
||||
// ######################################################################
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for NVPs for JSON archives
|
||||
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||
template <class T> inline
|
||||
void prologue( JSONOutputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
//! Prologue for NVPs for JSON archives
|
||||
template <class T> inline
|
||||
void prologue( JSONInputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for NVPs for JSON archives
|
||||
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||
template <class T> inline
|
||||
void epilogue( JSONOutputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
//! Epilogue for NVPs for JSON archives
|
||||
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||
template <class T> inline
|
||||
void epilogue( JSONInputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for SizeTags for JSON archives
|
||||
/*! SizeTags are strictly ignored for JSON, they just indicate
|
||||
that the current node should be made into an array */
|
||||
template <class T> inline
|
||||
void prologue( JSONOutputArchive & ar, SizeTag<T> const & )
|
||||
{
|
||||
ar.makeArray();
|
||||
}
|
||||
|
||||
//! Prologue for SizeTags for JSON archives
|
||||
template <class T> inline
|
||||
void prologue( JSONInputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for SizeTags for JSON archives
|
||||
/*! SizeTags are strictly ignored for JSON */
|
||||
template <class T> inline
|
||||
void epilogue( JSONOutputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
//! Epilogue for SizeTags for JSON archives
|
||||
template <class T> inline
|
||||
void epilogue( JSONInputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for all other types for JSON archives (except minimal types)
|
||||
/*! Starts a new node, named either automatically or by some NVP,
|
||||
that may be given data by the type about to be archived
|
||||
|
||||
Minimal types do not start or finish nodes */
|
||||
template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
|
||||
traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value ||
|
||||
traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
|
||||
inline void prologue( JSONOutputArchive & ar, T const & )
|
||||
{
|
||||
ar.startNode();
|
||||
}
|
||||
|
||||
//! Prologue for all other types for JSON archives
|
||||
template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
|
||||
traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value ||
|
||||
traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
|
||||
inline void prologue( JSONInputArchive & ar, T const & )
|
||||
{
|
||||
ar.startNode();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for all other types other for JSON archives (except minimal types
|
||||
/*! Finishes the node created in the prologue
|
||||
|
||||
Minimal types do not start or finish nodes */
|
||||
template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
|
||||
traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value ||
|
||||
traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
|
||||
inline void epilogue( JSONOutputArchive & ar, T const & )
|
||||
{
|
||||
ar.finishNode();
|
||||
}
|
||||
|
||||
//! Epilogue for all other types other for JSON archives
|
||||
template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
|
||||
traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value ||
|
||||
traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
|
||||
inline void epilogue( JSONInputArchive & ar, T const & )
|
||||
{
|
||||
ar.finishNode();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for arithmetic types for JSON archives
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
|
||||
void prologue( JSONOutputArchive & ar, T const & )
|
||||
{
|
||||
ar.writeName();
|
||||
}
|
||||
|
||||
//! Prologue for arithmetic types for JSON archives
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
|
||||
void prologue( JSONInputArchive &, T const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for arithmetic types for JSON archives
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
|
||||
void epilogue( JSONOutputArchive &, T const & )
|
||||
{ }
|
||||
|
||||
//! Epilogue for arithmetic types for JSON archives
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
|
||||
void epilogue( JSONInputArchive &, T const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for strings for JSON archives
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void prologue(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const &)
|
||||
{
|
||||
ar.writeName();
|
||||
}
|
||||
|
||||
//! Prologue for strings for JSON archives
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void prologue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for strings for JSON archives
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void epilogue(JSONOutputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
|
||||
{ }
|
||||
|
||||
//! Epilogue for strings for JSON archives
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void epilogue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
// Common JSONArchive serialization functions
|
||||
// ######################################################################
|
||||
//! Serializing NVP types to JSON
|
||||
template <class T> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive & ar, NameValuePair<T> const & t )
|
||||
{
|
||||
ar.setNextName( t.name );
|
||||
ar( t.value );
|
||||
}
|
||||
|
||||
template <class T> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, NameValuePair<T> & t )
|
||||
{
|
||||
ar.setNextName( t.name );
|
||||
ar( t.value );
|
||||
}
|
||||
|
||||
//! Saving for arithmetic to JSON
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, T const & t)
|
||||
{
|
||||
ar.saveValue( t );
|
||||
}
|
||||
|
||||
//! Loading arithmetic from JSON
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, T & t)
|
||||
{
|
||||
ar.loadValue( t );
|
||||
}
|
||||
|
||||
//! saving string to JSON
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
||||
{
|
||||
ar.saveValue( str );
|
||||
}
|
||||
|
||||
//! loading string from JSON
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
|
||||
{
|
||||
ar.loadValue( str );
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Saving SizeTags to JSON
|
||||
template <class T> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive &, SizeTag<T> const & )
|
||||
{
|
||||
// nothing to do here, we don't explicitly save the size
|
||||
}
|
||||
|
||||
//! Loading SizeTags from JSON
|
||||
template <class T> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, SizeTag<T> & st )
|
||||
{
|
||||
ar.loadSize( st.size );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
// register archives for polymorphic support
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::JSONInputArchive)
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::JSONOutputArchive)
|
||||
|
||||
// tie input and output archives together
|
||||
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::JSONInputArchive, cereal::JSONOutputArchive)
|
||||
|
||||
#endif // CEREAL_ARCHIVES_JSON_HPP_
|
||||
245
libs/cereal/cereal/archives/portable_binary.hpp
Normal file
245
libs/cereal/cereal/archives/portable_binary.hpp
Normal file
@ -0,0 +1,245 @@
|
||||
/*! \file binary.hpp
|
||||
\brief Binary input and output archives */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
|
||||
#define CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace portable_binary_detail
|
||||
{
|
||||
//! Returns true if the current machine is little endian
|
||||
/*! @ingroup Internal */
|
||||
inline bool is_little_endian()
|
||||
{
|
||||
static std::int32_t test = 1;
|
||||
return *reinterpret_cast<std::int8_t*>( &test ) == 1;
|
||||
}
|
||||
|
||||
//! Swaps the order of bytes for some chunk of memory
|
||||
/*! @param data The data as a uint8_t pointer
|
||||
@tparam DataSize The true size of the data
|
||||
@ingroup Internal */
|
||||
template <std::size_t DataSize>
|
||||
inline void swap_bytes( std::uint8_t * data )
|
||||
{
|
||||
for( std::size_t i = 0, end = DataSize / 2; i < end; ++i )
|
||||
std::swap( data[i], data[DataSize - i - 1] );
|
||||
}
|
||||
} // end namespace portable_binary_detail
|
||||
|
||||
// ######################################################################
|
||||
//! An output archive designed to save data in a compact binary representation portable over different architectures
|
||||
/*! This archive outputs data to a stream in an extremely compact binary
|
||||
representation with as little extra metadata as possible.
|
||||
|
||||
This archive will record the endianness of the data and assuming that
|
||||
the user takes care of ensuring serialized types are the same size
|
||||
across machines, is portable over different architectures.
|
||||
|
||||
When using a binary archive and a file stream, you must use the
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
inadvertently.
|
||||
|
||||
\warning This archive has not been thoroughly tested across different architectures.
|
||||
Please report any issues, optimizations, or feature requests at
|
||||
<a href="www.github.com/USCiLab/cereal">the project github</a>.
|
||||
|
||||
\ingroup Archives */
|
||||
class PortableBinaryOutputArchive : public OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>
|
||||
{
|
||||
public:
|
||||
//! Construct, outputting to the provided stream
|
||||
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
|
||||
even cout! */
|
||||
PortableBinaryOutputArchive(std::ostream & stream) :
|
||||
OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>(this),
|
||||
itsStream(stream)
|
||||
{
|
||||
this->operator()( portable_binary_detail::is_little_endian() );
|
||||
}
|
||||
|
||||
//! Writes size bytes of data to the output stream
|
||||
void saveBinary( const void * data, std::size_t size )
|
||||
{
|
||||
auto const writtenSize = static_cast<std::size_t>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size ) );
|
||||
|
||||
if(writtenSize != size)
|
||||
throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream & itsStream;
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
//! An input archive designed to load data saved using PortableBinaryOutputArchive
|
||||
/*! This archive outputs data to a stream in an extremely compact binary
|
||||
representation with as little extra metadata as possible.
|
||||
|
||||
This archive will load the endianness of the serialized data and
|
||||
if necessary transform it to match that of the local machine. This comes
|
||||
at a significant performance cost compared to non portable archives if
|
||||
the transformation is necessary, and also causes a small performance hit
|
||||
even if it is not necessary.
|
||||
|
||||
It is recommended to use portable archives only if you know that you will
|
||||
be sending binary data to machines with different endianness.
|
||||
|
||||
The archive will do nothing to ensure types are the same size - that is
|
||||
the responsibility of the user.
|
||||
|
||||
When using a binary archive and a file stream, you must use the
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
inadvertently.
|
||||
|
||||
\warning This archive has not been thoroughly tested across different architectures.
|
||||
Please report any issues, optimizations, or feature requests at
|
||||
<a href="www.github.com/USCiLab/cereal">the project github</a>.
|
||||
|
||||
\ingroup Archives */
|
||||
class PortableBinaryInputArchive : public InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>
|
||||
{
|
||||
public:
|
||||
//! Construct, loading from the provided stream
|
||||
/*! @param stream The stream to read from. */
|
||||
PortableBinaryInputArchive(std::istream & stream) :
|
||||
InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>(this),
|
||||
itsStream(stream),
|
||||
itsConvertEndianness( false )
|
||||
{
|
||||
bool streamLittleEndian;
|
||||
this->operator()( streamLittleEndian );
|
||||
itsConvertEndianness = portable_binary_detail::is_little_endian() ^ streamLittleEndian;
|
||||
}
|
||||
|
||||
//! Reads size bytes of data from the input stream
|
||||
/*! @param data The data to save
|
||||
@param size The number of bytes in the data
|
||||
@tparam DataSize T The size of the actual type of the data elements being loaded */
|
||||
template <std::size_t DataSize>
|
||||
void loadBinary( void * const data, std::size_t size )
|
||||
{
|
||||
// load data
|
||||
auto const readSize = static_cast<std::size_t>( itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size ) );
|
||||
|
||||
if(readSize != size)
|
||||
throw Exception("Failed to read " + std::to_string(size) + " bytes from input stream! Read " + std::to_string(readSize));
|
||||
|
||||
// flip bits if needed
|
||||
if( itsConvertEndianness )
|
||||
{
|
||||
std::uint8_t * ptr = reinterpret_cast<std::uint8_t*>( data );
|
||||
for( std::size_t i = 0; i < size; i += DataSize )
|
||||
portable_binary_detail::swap_bytes<DataSize>( ptr );
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::istream & itsStream;
|
||||
bool itsConvertEndianness; //!< If set to true, we will need to swap bytes upon loading
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
// Common BinaryArchive serialization functions
|
||||
|
||||
//! Saving for POD types to portable binary
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, T const & t)
|
||||
{
|
||||
static_assert( !std::is_floating_point<T>::value ||
|
||||
(std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
|
||||
"Portable binary only supports IEEE 754 standardized floating point" );
|
||||
ar.saveBinary(std::addressof(t), sizeof(t));
|
||||
}
|
||||
|
||||
//! Loading for POD types from portable binary
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, T & t)
|
||||
{
|
||||
static_assert( !std::is_floating_point<T>::value ||
|
||||
(std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
|
||||
"Portable binary only supports IEEE 754 standardized floating point" );
|
||||
ar.template loadBinary<sizeof(T)>(std::addressof(t), sizeof(t));
|
||||
}
|
||||
|
||||
//! Serializing NVP types to portable binary
|
||||
template <class Archive, class T> inline
|
||||
CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, NameValuePair<T> & t )
|
||||
{
|
||||
ar( t.value );
|
||||
}
|
||||
|
||||
//! Serializing SizeTags to portable binary
|
||||
template <class Archive, class T> inline
|
||||
CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, SizeTag<T> & t )
|
||||
{
|
||||
ar( t.size );
|
||||
}
|
||||
|
||||
//! Saving binary data to portable binary
|
||||
template <class T> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, BinaryData<T> const & bd)
|
||||
{
|
||||
typedef typename std::remove_pointer<T>::type TT;
|
||||
static_assert( !std::is_floating_point<TT>::value ||
|
||||
(std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
|
||||
"Portable binary only supports IEEE 754 standardized floating point" );
|
||||
|
||||
ar.saveBinary( bd.data, static_cast<std::size_t>( bd.size ) );
|
||||
}
|
||||
|
||||
//! Loading binary data from portable binary
|
||||
template <class T> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, BinaryData<T> & bd)
|
||||
{
|
||||
typedef typename std::remove_pointer<T>::type TT;
|
||||
static_assert( !std::is_floating_point<TT>::value ||
|
||||
(std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
|
||||
"Portable binary only supports IEEE 754 standardized floating point" );
|
||||
|
||||
ar.template loadBinary<sizeof(TT)>( bd.data, static_cast<std::size_t>( bd.size ) );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
// register archives for polymorphic support
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryOutputArchive)
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryInputArchive)
|
||||
|
||||
// tie input and output archives together
|
||||
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive)
|
||||
|
||||
#endif // CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
|
||||
882
libs/cereal/cereal/archives/xml.hpp
Normal file
882
libs/cereal/cereal/archives/xml.hpp
Normal file
@ -0,0 +1,882 @@
|
||||
/*! \file xml.hpp
|
||||
\brief XML input and output archives */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_ARCHIVES_XML_HPP_
|
||||
#define CEREAL_ARCHIVES_XML_HPP_
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/details/util.hpp>
|
||||
|
||||
#include <cereal/external/rapidxml/rapidxml.hpp>
|
||||
#include <cereal/external/rapidxml/rapidxml_print.hpp>
|
||||
#include <cereal/external/base64.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace xml_detail
|
||||
{
|
||||
#ifndef CEREAL_XML_STRING_VALUE
|
||||
//! The default name for the root node in a cereal xml archive.
|
||||
/*! You can define CEREAL_XML_STRING_VALUE to be different assuming you do so
|
||||
before this file is included. */
|
||||
#define CEREAL_XML_STRING_VALUE "cereal"
|
||||
#endif // CEREAL_XML_STRING_VALUE
|
||||
|
||||
//! The name given to the root node in a cereal xml archive
|
||||
static const char * CEREAL_XML_STRING = CEREAL_XML_STRING_VALUE;
|
||||
|
||||
//! Returns true if the character is whitespace
|
||||
inline bool isWhitespace( char c )
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
|
||||
}
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! An output archive designed to save data to XML
|
||||
/*! This archive uses RapidXML to build an in memory XML tree of the
|
||||
data it serializes before outputting it to its stream upon destruction.
|
||||
The envisioned way of using this archive is in an RAII fashion, letting
|
||||
the automatic destruction of the object cause the flush to its stream.
|
||||
|
||||
XML archives provides a human readable output but at decreased
|
||||
performance (both in time and space) compared to binary archives.
|
||||
|
||||
XML benefits greatly from name-value pairs, which if present, will
|
||||
name the nodes in the output. If these are not present, each level
|
||||
of the output tree will be given an automatically generated delimited name.
|
||||
|
||||
The precision of the output archive controls the number of decimals output
|
||||
for floating point numbers and should be sufficiently large (i.e. at least 20)
|
||||
if there is a desire to have binary equality between the numbers output and
|
||||
those read in. In general you should expect a loss of precision when going
|
||||
from floating point to text and back.
|
||||
|
||||
XML archives can optionally print the type of everything they serialize, which
|
||||
adds an attribute to each node.
|
||||
|
||||
XML archives do not output the size information for any dynamically sized structure
|
||||
and instead infer it from the number of children for a node. This means that data
|
||||
can be hand edited for dynamic sized structures and will still be readable. This
|
||||
is accomplished through the cereal::SizeTag object, which will also add an attribute
|
||||
to its parent field.
|
||||
\ingroup Archives */
|
||||
class XMLOutputArchive : public OutputArchive<XMLOutputArchive>, public traits::TextArchive
|
||||
{
|
||||
public:
|
||||
/*! @name Common Functionality
|
||||
Common use cases for directly interacting with an XMLOutputArchive */
|
||||
//! @{
|
||||
|
||||
//! A class containing various advanced options for the XML archive
|
||||
class Options
|
||||
{
|
||||
public:
|
||||
//! Default options
|
||||
static Options Default(){ return Options(); }
|
||||
|
||||
//! Default options with no indentation
|
||||
static Options NoIndent(){ return Options( std::numeric_limits<double>::max_digits10, false ); }
|
||||
|
||||
//! Specify specific options for the XMLOutputArchive
|
||||
/*! @param precision The precision used for floating point numbers
|
||||
@param indent Whether to indent each line of XML
|
||||
@param outputType Whether to output the type of each serialized object as an attribute */
|
||||
explicit Options( int precision = std::numeric_limits<double>::max_digits10,
|
||||
bool indent = true,
|
||||
bool outputType = false ) :
|
||||
itsPrecision( precision ),
|
||||
itsIndent( indent ),
|
||||
itsOutputType( outputType ) { }
|
||||
|
||||
private:
|
||||
friend class XMLOutputArchive;
|
||||
int itsPrecision;
|
||||
bool itsIndent;
|
||||
bool itsOutputType;
|
||||
};
|
||||
|
||||
//! Construct, outputting to the provided stream upon destruction
|
||||
/*! @param stream The stream to output to. Note that XML is only guaranteed to flush
|
||||
its output to the stream upon destruction.
|
||||
@param options The XML specific options to use. See the Options struct
|
||||
for the values of default parameters */
|
||||
XMLOutputArchive( std::ostream & stream, Options const & options = Options::Default() ) :
|
||||
OutputArchive<XMLOutputArchive>(this),
|
||||
itsStream(stream),
|
||||
itsOutputType( options.itsOutputType ),
|
||||
itsIndent( options.itsIndent )
|
||||
{
|
||||
// rapidxml will delete all allocations when xml_document is cleared
|
||||
auto node = itsXML.allocate_node( rapidxml::node_declaration );
|
||||
node->append_attribute( itsXML.allocate_attribute( "version", "1.0" ) );
|
||||
node->append_attribute( itsXML.allocate_attribute( "encoding", "utf-8" ) );
|
||||
itsXML.append_node( node );
|
||||
|
||||
// allocate root node
|
||||
auto root = itsXML.allocate_node( rapidxml::node_element, xml_detail::CEREAL_XML_STRING );
|
||||
itsXML.append_node( root );
|
||||
itsNodes.emplace( root );
|
||||
|
||||
// set attributes on the streams
|
||||
itsStream << std::boolalpha;
|
||||
itsStream.precision( options.itsPrecision );
|
||||
itsOS << std::boolalpha;
|
||||
itsOS.precision( options.itsPrecision );
|
||||
}
|
||||
|
||||
//! Destructor, flushes the XML
|
||||
~XMLOutputArchive()
|
||||
{
|
||||
const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
|
||||
rapidxml::print( itsStream, itsXML, flags );
|
||||
itsXML.clear();
|
||||
}
|
||||
|
||||
//! Saves some binary data, encoded as a base64 string, with an optional name
|
||||
/*! This can be called directly by users and it will automatically create a child node for
|
||||
the current XML node, populate it with a base64 encoded string, and optionally name
|
||||
it. The node will be finished after it has been populated. */
|
||||
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
|
||||
{
|
||||
itsNodes.top().name = name;
|
||||
|
||||
startNode();
|
||||
|
||||
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
|
||||
saveValue( base64string );
|
||||
|
||||
if( itsOutputType )
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
|
||||
|
||||
finishNode();
|
||||
};
|
||||
|
||||
//! @}
|
||||
/*! @name Internal Functionality
|
||||
Functionality designed for use by those requiring control over the inner mechanisms of
|
||||
the XMLOutputArchive */
|
||||
//! @{
|
||||
|
||||
//! Creates a new node that is a child of the node at the top of the stack
|
||||
/*! Nodes will be given a name that has either been pre-set by a name value pair,
|
||||
or generated based upon a counter unique to the parent node. If you want to
|
||||
give a node a specific name, use setNextName prior to calling startNode.
|
||||
|
||||
The node will then be pushed onto the node stack. */
|
||||
void startNode()
|
||||
{
|
||||
// generate a name for this new node
|
||||
const auto nameString = itsNodes.top().getValueName();
|
||||
|
||||
// allocate strings for all of the data in the XML object
|
||||
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
|
||||
|
||||
// insert into the XML
|
||||
auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
|
||||
itsNodes.top().node->append_node( node );
|
||||
itsNodes.emplace( node );
|
||||
}
|
||||
|
||||
//! Designates the most recently added node as finished
|
||||
void finishNode()
|
||||
{
|
||||
itsNodes.pop();
|
||||
}
|
||||
|
||||
//! Sets the name for the next node created with startNode
|
||||
void setNextName( const char * name )
|
||||
{
|
||||
itsNodes.top().name = name;
|
||||
}
|
||||
|
||||
//! Saves some data, encoded as a string, into the current top level node
|
||||
/*! The data will be be named with the most recent name if one exists,
|
||||
otherwise it will be given some default delimited value that depends upon
|
||||
the parent node */
|
||||
template <class T> inline
|
||||
void saveValue( T const & value )
|
||||
{
|
||||
itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
|
||||
itsOS << value << std::ends;
|
||||
|
||||
const auto strValue = itsOS.str();
|
||||
|
||||
// If the first or last character is a whitespace, add xml:space attribute
|
||||
// the string always contains a '\0' added by std::ends, so the last character is at len-2 and an 'empty'
|
||||
// string has a length of 1 or lower
|
||||
const auto len = strValue.length();
|
||||
if ( len > 1 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 2] ) ) )
|
||||
{
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
|
||||
}
|
||||
|
||||
// allocate strings for all of the data in the XML object
|
||||
auto dataPtr = itsXML.allocate_string( itsOS.str().c_str(), itsOS.str().length() + 1 );
|
||||
|
||||
// insert into the XML
|
||||
itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
|
||||
}
|
||||
|
||||
//! Overload for uint8_t prevents them from being serialized as characters
|
||||
void saveValue( uint8_t const & value )
|
||||
{
|
||||
saveValue( static_cast<uint32_t>( value ) );
|
||||
}
|
||||
|
||||
//! Overload for int8_t prevents them from being serialized as characters
|
||||
void saveValue( int8_t const & value )
|
||||
{
|
||||
saveValue( static_cast<int32_t>( value ) );
|
||||
}
|
||||
|
||||
//! Causes the type to be appended as an attribute to the most recently made node if output type is set to true
|
||||
template <class T> inline
|
||||
void insertType()
|
||||
{
|
||||
if( !itsOutputType )
|
||||
return;
|
||||
|
||||
// generate a name for this new node
|
||||
const auto nameString = util::demangledName<T>();
|
||||
|
||||
// allocate strings for all of the data in the XML object
|
||||
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
|
||||
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
|
||||
}
|
||||
|
||||
//! Appends an attribute to the current top level node
|
||||
void appendAttribute( const char * name, const char * value )
|
||||
{
|
||||
auto namePtr = itsXML.allocate_string( name );
|
||||
auto valuePtr = itsXML.allocate_string( value );
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
|
||||
}
|
||||
|
||||
protected:
|
||||
//! A struct that contains metadata about a node
|
||||
struct NodeInfo
|
||||
{
|
||||
NodeInfo( rapidxml::xml_node<> * n = nullptr,
|
||||
const char * nm = nullptr ) :
|
||||
node( n ),
|
||||
counter( 0 ),
|
||||
name( nm )
|
||||
{ }
|
||||
|
||||
rapidxml::xml_node<> * node; //!< A pointer to this node
|
||||
size_t counter; //!< The counter for naming child nodes
|
||||
const char * name; //!< The name for the next child node
|
||||
|
||||
//! Gets the name for the next child node created from this node
|
||||
/*! The name will be automatically generated using the counter if
|
||||
a name has not been previously set. If a name has been previously
|
||||
set, that name will be returned only once */
|
||||
std::string getValueName()
|
||||
{
|
||||
if( name )
|
||||
{
|
||||
auto n = name;
|
||||
name = nullptr;
|
||||
return {n};
|
||||
}
|
||||
else
|
||||
return "value" + std::to_string( counter++ ) + "\0";
|
||||
}
|
||||
}; // NodeInfo
|
||||
|
||||
//! @}
|
||||
|
||||
private:
|
||||
std::ostream & itsStream; //!< The output stream
|
||||
rapidxml::xml_document<> itsXML; //!< The XML document
|
||||
std::stack<NodeInfo> itsNodes; //!< A stack of nodes added to the document
|
||||
std::ostringstream itsOS; //!< Used to format strings internally
|
||||
bool itsOutputType; //!< Controls whether type information is printed
|
||||
bool itsIndent; //!< Controls whether indenting is used
|
||||
}; // XMLOutputArchive
|
||||
|
||||
// ######################################################################
|
||||
//! An output archive designed to load data from XML
|
||||
/*! This archive uses RapidXML to build an in memory XML tree of the
|
||||
data in the stream it is given before loading any types serialized.
|
||||
|
||||
Input XML should have been produced by the XMLOutputArchive. Data can
|
||||
only be added to dynamically sized containers - the input archive will
|
||||
determine their size by looking at the number of child nodes. Data that
|
||||
did not originate from an XMLOutputArchive is not officially supported,
|
||||
but may be possible to use if properly formatted.
|
||||
|
||||
The XMLInputArchive does not require that nodes are loaded in the same
|
||||
order they were saved by XMLOutputArchive. Using name value pairs (NVPs),
|
||||
it is possible to load in an out of order fashion or otherwise skip/select
|
||||
specific nodes to load.
|
||||
|
||||
The default behavior of the input archive is to read sequentially starting
|
||||
with the first node and exploring its children. When a given NVP does
|
||||
not match the read in name for a node, the archive will search for that
|
||||
node at the current level and load it if it exists. After loading an out of
|
||||
order node, the archive will then proceed back to loading sequentially from
|
||||
its new position.
|
||||
|
||||
Consider this simple example where loading of some data is skipped:
|
||||
|
||||
@code{cpp}
|
||||
// imagine the input file has someData(1-9) saved in order at the top level node
|
||||
ar( someData1, someData2, someData3 ); // XML loads in the order it sees in the file
|
||||
ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
|
||||
// match expected NVP name, so we search
|
||||
// for the given NVP and load that value
|
||||
ar( someData7, someData8, someData9 ); // with no NVP given, loading resumes at its
|
||||
// current location, proceeding sequentially
|
||||
@endcode
|
||||
|
||||
\ingroup Archives */
|
||||
class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
|
||||
{
|
||||
public:
|
||||
/*! @name Common Functionality
|
||||
Common use cases for directly interacting with an XMLInputArchive */
|
||||
//! @{
|
||||
|
||||
//! Construct, reading in from the provided stream
|
||||
/*! Reads in an entire XML document from some stream and parses it as soon
|
||||
as serialization starts
|
||||
|
||||
@param stream The stream to read from. Can be a stringstream or a file. */
|
||||
XMLInputArchive( std::istream & stream ) :
|
||||
InputArchive<XMLInputArchive>( this ),
|
||||
itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
|
||||
{
|
||||
try
|
||||
{
|
||||
itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
|
||||
itsXML.parse<rapidxml::parse_trim_whitespace | rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
|
||||
}
|
||||
catch( rapidxml::parse_error const & )
|
||||
{
|
||||
//std::cerr << "-----Original-----" << std::endl;
|
||||
//stream.seekg(0);
|
||||
//std::cout << std::string( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() ) << std::endl;
|
||||
|
||||
//std::cerr << "-----Error-----" << std::endl;
|
||||
//std::cerr << e.what() << std::endl;
|
||||
//std::cerr << e.where<char>() << std::endl;
|
||||
throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
|
||||
}
|
||||
|
||||
// Parse the root
|
||||
auto root = itsXML.first_node( xml_detail::CEREAL_XML_STRING );
|
||||
if( root == nullptr )
|
||||
throw Exception("Could not detect cereal root node - likely due to empty or invalid input");
|
||||
else
|
||||
itsNodes.emplace( root );
|
||||
}
|
||||
|
||||
//! Loads some binary data, encoded as a base64 string, optionally specified by some name
|
||||
/*! This will automatically start and finish a node to load the data, and can be called directly by
|
||||
users.
|
||||
|
||||
Note that this follows the same ordering rules specified in the class description in regards
|
||||
to loading in/out of order */
|
||||
void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
|
||||
{
|
||||
setNextName( name );
|
||||
startNode();
|
||||
|
||||
std::string encoded;
|
||||
loadValue( encoded );
|
||||
|
||||
auto decoded = base64::decode( encoded );
|
||||
|
||||
if( size != decoded.size() )
|
||||
throw Exception("Decoded binary data size does not match specified size");
|
||||
|
||||
std::memcpy( data, decoded.data(), decoded.size() );
|
||||
|
||||
finishNode();
|
||||
};
|
||||
|
||||
//! @}
|
||||
/*! @name Internal Functionality
|
||||
Functionality designed for use by those requiring control over the inner mechanisms of
|
||||
the XMLInputArchive */
|
||||
//! @{
|
||||
|
||||
//! Prepares to start reading the next node
|
||||
/*! This places the next node to be parsed onto the nodes stack.
|
||||
|
||||
By default our strategy is to start with the document root node and then
|
||||
recursively iterate through all children in the order they show up in the document.
|
||||
We don't need to know NVPs do to this; we'll just blindly load in the order things appear in.
|
||||
|
||||
We check to see if the specified NVP matches what the next automatically loaded node is. If they
|
||||
match, we just continue as normal, going in order. If they don't match, we attempt to find a node
|
||||
named after the NVP that is being loaded. If that NVP does not exist, we throw an exception. */
|
||||
void startNode()
|
||||
{
|
||||
auto next = itsNodes.top().child; // By default we would move to the next child node
|
||||
auto const expectedName = itsNodes.top().name; // this is the expected name from the NVP, if provided
|
||||
|
||||
// If we were given an NVP name, look for it in the current level of the document.
|
||||
// We only need to do this if either we have exhausted the siblings of the current level or
|
||||
// the NVP name does not match the name of the node we would normally read next
|
||||
if( expectedName && ( next == nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
|
||||
{
|
||||
next = itsNodes.top().search( expectedName );
|
||||
|
||||
if( next == nullptr )
|
||||
throw Exception("XML Parsing failed - provided NVP not found");
|
||||
}
|
||||
|
||||
itsNodes.emplace( next );
|
||||
}
|
||||
|
||||
//! Finishes reading the current node
|
||||
void finishNode()
|
||||
{
|
||||
// remove current
|
||||
itsNodes.pop();
|
||||
|
||||
// advance parent
|
||||
itsNodes.top().advance();
|
||||
|
||||
// Reset name
|
||||
itsNodes.top().name = nullptr;
|
||||
}
|
||||
|
||||
//! Retrieves the current node name
|
||||
//! will return @c nullptr if the node does not have a name
|
||||
const char * getNodeName() const
|
||||
{
|
||||
return itsNodes.top().node->name();
|
||||
}
|
||||
|
||||
//! Sets the name for the next node created with startNode
|
||||
void setNextName( const char * name )
|
||||
{
|
||||
itsNodes.top().name = name;
|
||||
}
|
||||
|
||||
//! Loads a bool from the current top node
|
||||
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
|
||||
std::is_same<T, bool>::value> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
std::istringstream is( itsNodes.top().node->value() );
|
||||
is.setf( std::ios::boolalpha );
|
||||
is >> value;
|
||||
}
|
||||
|
||||
//! Loads a char (signed or unsigned) from the current top node
|
||||
template <class T, traits::EnableIf<std::is_integral<T>::value,
|
||||
!std::is_same<T, bool>::value,
|
||||
sizeof(T) == sizeof(char)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
|
||||
}
|
||||
|
||||
//! Load an int8_t from the current top node (ensures we parse entire number)
|
||||
void loadValue( int8_t & value )
|
||||
{
|
||||
int32_t val; loadValue( val ); value = static_cast<int8_t>( val );
|
||||
}
|
||||
|
||||
//! Load a uint8_t from the current top node (ensures we parse entire number)
|
||||
void loadValue( uint8_t & value )
|
||||
{
|
||||
uint32_t val; loadValue( val ); value = static_cast<uint8_t>( val );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as an unsigned long from the current top node
|
||||
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
|
||||
!std::is_same<T, bool>::value,
|
||||
!std::is_same<T, unsigned char>::value,
|
||||
sizeof(T) < sizeof(long long)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as an unsigned long long from the current top node
|
||||
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
|
||||
!std::is_same<T, bool>::value,
|
||||
sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as an int from the current top node
|
||||
template <class T, traits::EnableIf<std::is_signed<T>::value,
|
||||
!std::is_same<T, char>::value,
|
||||
sizeof(T) <= sizeof(int)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a long from the current top node
|
||||
template <class T, traits::EnableIf<std::is_signed<T>::value,
|
||||
(sizeof(T) > sizeof(int)),
|
||||
sizeof(T) <= sizeof(long)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a long long from the current top node
|
||||
template <class T, traits::EnableIf<std::is_signed<T>::value,
|
||||
(sizeof(T) > sizeof(long)),
|
||||
sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a float from the current top node
|
||||
void loadValue( float & value )
|
||||
{
|
||||
try
|
||||
{
|
||||
value = std::stof( itsNodes.top().node->value() );
|
||||
}
|
||||
catch( std::out_of_range const & )
|
||||
{
|
||||
// special case for denormalized values
|
||||
std::istringstream is( itsNodes.top().node->value() );
|
||||
is >> value;
|
||||
if( std::fpclassify( value ) != FP_SUBNORMAL )
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a double from the current top node
|
||||
void loadValue( double & value )
|
||||
{
|
||||
try
|
||||
{
|
||||
value = std::stod( itsNodes.top().node->value() );
|
||||
}
|
||||
catch( std::out_of_range const & )
|
||||
{
|
||||
// special case for denormalized values
|
||||
std::istringstream is( itsNodes.top().node->value() );
|
||||
is >> value;
|
||||
if( std::fpclassify( value ) != FP_SUBNORMAL )
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a long double from the current top node
|
||||
void loadValue( long double & value )
|
||||
{
|
||||
try
|
||||
{
|
||||
value = std::stold( itsNodes.top().node->value() );
|
||||
}
|
||||
catch( std::out_of_range const & )
|
||||
{
|
||||
// special case for denormalized values
|
||||
std::istringstream is( itsNodes.top().node->value() );
|
||||
is >> value;
|
||||
if( std::fpclassify( value ) != FP_SUBNORMAL )
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
//! Loads a string from the current node from the current top node
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
|
||||
{
|
||||
std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
|
||||
|
||||
str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
|
||||
std::istreambuf_iterator<CharT, Traits>() );
|
||||
}
|
||||
|
||||
//! Loads the size of the current top node
|
||||
template <class T> inline
|
||||
void loadSize( T & value )
|
||||
{
|
||||
value = getNumChildren( itsNodes.top().node );
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Gets the number of children (usually interpreted as size) for the specified node
|
||||
static size_t getNumChildren( rapidxml::xml_node<> * node )
|
||||
{
|
||||
size_t size = 0;
|
||||
node = node->first_node(); // get first child
|
||||
|
||||
while( node != nullptr )
|
||||
{
|
||||
++size;
|
||||
node = node->next_sibling();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
//! A struct that contains metadata about a node
|
||||
/*! Keeps track of some top level node, its number of
|
||||
remaining children, and the current active child node */
|
||||
struct NodeInfo
|
||||
{
|
||||
NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
|
||||
node( n ),
|
||||
child( n->first_node() ),
|
||||
size( XMLInputArchive::getNumChildren( n ) ),
|
||||
name( nullptr )
|
||||
{ }
|
||||
|
||||
//! Advances to the next sibling node of the child
|
||||
/*! If this is the last sibling child will be null after calling */
|
||||
void advance()
|
||||
{
|
||||
if( size > 0 )
|
||||
{
|
||||
--size;
|
||||
child = child->next_sibling();
|
||||
}
|
||||
}
|
||||
|
||||
//! Searches for a child with the given name in this node
|
||||
/*! @param searchName The name to search for (must be null terminated)
|
||||
@return The node if found, nullptr otherwise */
|
||||
rapidxml::xml_node<> * search( const char * searchName )
|
||||
{
|
||||
if( searchName )
|
||||
{
|
||||
size_t new_size = XMLInputArchive::getNumChildren( node );
|
||||
const size_t name_size = rapidxml::internal::measure( searchName );
|
||||
|
||||
for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
|
||||
{
|
||||
if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
|
||||
{
|
||||
size = new_size;
|
||||
child = new_child;
|
||||
|
||||
return new_child;
|
||||
}
|
||||
--new_size;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rapidxml::xml_node<> * node; //!< A pointer to this node
|
||||
rapidxml::xml_node<> * child; //!< A pointer to its current child
|
||||
size_t size; //!< The remaining number of children for this node
|
||||
const char * name; //!< The NVP name for next next child node
|
||||
}; // NodeInfo
|
||||
|
||||
//! @}
|
||||
|
||||
private:
|
||||
std::vector<char> itsData; //!< The raw data loaded
|
||||
rapidxml::xml_document<> itsXML; //!< The XML document
|
||||
std::stack<NodeInfo> itsNodes; //!< A stack of nodes read from the document
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
// XMLArchive prologue and epilogue functions
|
||||
// ######################################################################
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for NVPs for XML output archives
|
||||
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||
template <class T> inline
|
||||
void prologue( XMLOutputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
//! Prologue for NVPs for XML input archives
|
||||
template <class T> inline
|
||||
void prologue( XMLInputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for NVPs for XML output archives
|
||||
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||
template <class T> inline
|
||||
void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
//! Epilogue for NVPs for XML input archives
|
||||
template <class T> inline
|
||||
void epilogue( XMLInputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for SizeTags for XML output archives
|
||||
/*! SizeTags do not start or finish nodes */
|
||||
template <class T> inline
|
||||
void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
|
||||
{
|
||||
ar.appendAttribute( "size", "dynamic" );
|
||||
}
|
||||
|
||||
template <class T> inline
|
||||
void prologue( XMLInputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
//! Epilogue for SizeTags for XML output archives
|
||||
/*! SizeTags do not start or finish nodes */
|
||||
template <class T> inline
|
||||
void epilogue( XMLOutputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
template <class T> inline
|
||||
void epilogue( XMLInputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for all other types for XML output archives (except minimal types)
|
||||
/*! Starts a new node, named either automatically or by some NVP,
|
||||
that may be given data by the type about to be archived
|
||||
|
||||
Minimal types do not start or end nodes */
|
||||
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
|
||||
traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
|
||||
void prologue( XMLOutputArchive & ar, T const & )
|
||||
{
|
||||
ar.startNode();
|
||||
ar.insertType<T>();
|
||||
}
|
||||
|
||||
//! Prologue for all other types for XML input archives (except minimal types)
|
||||
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
|
||||
traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
|
||||
void prologue( XMLInputArchive & ar, T const & )
|
||||
{
|
||||
ar.startNode();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for all other types other for XML output archives (except minimal types)
|
||||
/*! Finishes the node created in the prologue
|
||||
|
||||
Minimal types do not start or end nodes */
|
||||
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
|
||||
traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
|
||||
void epilogue( XMLOutputArchive & ar, T const & )
|
||||
{
|
||||
ar.finishNode();
|
||||
}
|
||||
|
||||
//! Epilogue for all other types other for XML output archives (except minimal types)
|
||||
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
|
||||
traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
|
||||
void epilogue( XMLInputArchive & ar, T const & )
|
||||
{
|
||||
ar.finishNode();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
// Common XMLArchive serialization functions
|
||||
// ######################################################################
|
||||
|
||||
//! Saving NVP types to XML
|
||||
template <class T> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive & ar, NameValuePair<T> const & t )
|
||||
{
|
||||
ar.setNextName( t.name );
|
||||
ar( t.value );
|
||||
}
|
||||
|
||||
//! Loading NVP types from XML
|
||||
template <class T> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, NameValuePair<T> & t )
|
||||
{
|
||||
ar.setNextName( t.name );
|
||||
ar( t.value );
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Saving SizeTags to XML
|
||||
template <class T> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
//! Loading SizeTags from XML
|
||||
template <class T> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, SizeTag<T> & st )
|
||||
{
|
||||
ar.loadSize( st.size );
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Saving for POD types to xml
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, T const & t)
|
||||
{
|
||||
ar.saveValue( t );
|
||||
}
|
||||
|
||||
//! Loading for POD types from xml
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, T & t)
|
||||
{
|
||||
ar.loadValue( t );
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! saving string to xml
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
||||
{
|
||||
ar.saveValue( str );
|
||||
}
|
||||
|
||||
//! loading string from xml
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
|
||||
{
|
||||
ar.loadValue( str );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
// register archives for polymorphic support
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive)
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
|
||||
|
||||
// tie input and output archives together
|
||||
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
|
||||
|
||||
#endif // CEREAL_ARCHIVES_XML_HPP_
|
||||
955
libs/cereal/cereal/cereal.hpp
Normal file
955
libs/cereal/cereal/cereal.hpp
Normal file
@ -0,0 +1,955 @@
|
||||
/*! \file cereal.hpp
|
||||
\brief Main cereal functionality */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_CEREAL_HPP_
|
||||
#define CEREAL_CEREAL_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
#include <cereal/macros.hpp>
|
||||
#include <cereal/details/traits.hpp>
|
||||
#include <cereal/details/helpers.hpp>
|
||||
#include <cereal/types/base_class.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// ######################################################################
|
||||
//! Creates a name value pair
|
||||
/*! @relates NameValuePair
|
||||
@ingroup Utility */
|
||||
template <class T> inline
|
||||
NameValuePair<T> make_nvp( std::string const & name, T && value )
|
||||
{
|
||||
return {name.c_str(), std::forward<T>(value)};
|
||||
}
|
||||
|
||||
//! Creates a name value pair
|
||||
/*! @relates NameValuePair
|
||||
@ingroup Utility */
|
||||
template <class T> inline
|
||||
NameValuePair<T> make_nvp( const char * name, T && value )
|
||||
{
|
||||
return {name, std::forward<T>(value)};
|
||||
}
|
||||
|
||||
//! Creates a name value pair for the variable T with the same name as the variable
|
||||
/*! @relates NameValuePair
|
||||
@ingroup Utility */
|
||||
#define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
|
||||
|
||||
// ######################################################################
|
||||
//! Convenience function to create binary data for both const and non const pointers
|
||||
/*! @param data Pointer to beginning of the data
|
||||
@param size The size in bytes of the data
|
||||
@relates BinaryData
|
||||
@ingroup Utility */
|
||||
template <class T> inline
|
||||
BinaryData<T> binary_data( T && data, size_t size )
|
||||
{
|
||||
return {std::forward<T>(data), size};
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Creates a size tag from some variable.
|
||||
/*! Will normally be used to serialize size (e.g. size()) information for
|
||||
variable size containers. If you have a variable sized container,
|
||||
the very first thing it serializes should be its size, wrapped in
|
||||
a SizeTag.
|
||||
|
||||
@relates SizeTag
|
||||
@ingroup Utility */
|
||||
template <class T>
|
||||
SizeTag<T> make_size_tag( T && sz )
|
||||
{
|
||||
return {std::forward<T>(sz)};
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Called before a type is serialized to set up any special archive state
|
||||
//! for processing some type
|
||||
/*! If designing a serializer that needs to set up any kind of special
|
||||
state or output extra information for a type, specialize this function
|
||||
for the archive type and the types that require the extra information.
|
||||
@ingroup Internal */
|
||||
template <class Archive, class T>
|
||||
void prologue( Archive & /* archive */, T const & /* data */)
|
||||
{ }
|
||||
|
||||
//! Called after a type is serialized to tear down any special archive state
|
||||
//! for processing some type
|
||||
/*! @ingroup Internal */
|
||||
template <class Archive, class T>
|
||||
void epilogue( Archive & /* archive */, T const & /* data */)
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Special flags for archives
|
||||
/*! AllowEmptyClassElision
|
||||
This allows for empty classes to be serialized even if they do not provide
|
||||
a serialization function. Classes with no data members are considered to be
|
||||
empty. Be warned that if this is enabled and you attempt to serialize an
|
||||
empty class with improperly formed serialize or load/save functions, no
|
||||
static error will occur - the error will propogate silently and your
|
||||
intended serialization functions may not be called. You can manually
|
||||
ensure that your classes that have custom serialization are correct
|
||||
by using the traits is_output_serializable and is_input_serializable
|
||||
in cereal/details/traits.hpp.
|
||||
@ingroup Internal */
|
||||
enum Flags { AllowEmptyClassElision = 1 };
|
||||
|
||||
// ######################################################################
|
||||
//! Registers a specific Archive type with cereal
|
||||
/*! This registration should be done once per archive. A good place to
|
||||
put this is immediately following the definition of your archive.
|
||||
Archive registration is only strictly necessary if you wish to
|
||||
support pointers to polymorphic data types. All archives that
|
||||
come with cereal are already registered.
|
||||
@ingroup Internal */
|
||||
#define CEREAL_REGISTER_ARCHIVE(Archive) \
|
||||
namespace cereal { namespace detail { \
|
||||
template <class T, class BindingTag> \
|
||||
typename polymorphic_serialization_support<Archive, T>::type \
|
||||
instantiate_polymorphic_binding( T*, Archive*, BindingTag, adl_tag ); \
|
||||
} } /* end namespaces */
|
||||
|
||||
// ######################################################################
|
||||
//! Defines a class version for some type
|
||||
/*! Versioning information is optional and adds some small amount of
|
||||
overhead to serialization. This overhead will occur both in terms of
|
||||
space in the archive (the version information for each class will be
|
||||
stored exactly once) as well as runtime (versioned serialization functions
|
||||
must check to see if they need to load or store version information).
|
||||
|
||||
Versioning is useful if you plan on fundamentally changing the way some
|
||||
type is serialized in the future. Versioned serialization functions
|
||||
cannot be used to load non-versioned data.
|
||||
|
||||
By default, all types have an assumed version value of zero. By
|
||||
using this macro, you may change the version number associated with
|
||||
some type. cereal will then use this value as a second parameter
|
||||
to your serialization functions.
|
||||
|
||||
The interface for the serialization functions is nearly identical
|
||||
to non-versioned serialization with the addition of a second parameter,
|
||||
const std::uint32_t version, which will be supplied with the correct
|
||||
version number. Serializing the version number on a save happens
|
||||
automatically.
|
||||
|
||||
Versioning cannot be mixed with non-versioned serialization functions.
|
||||
Having both types will result result in a compile time error. Data
|
||||
serialized without versioning cannot be loaded by a serialization
|
||||
function with added versioning support.
|
||||
|
||||
Example interface for versioning on a non-member serialize function:
|
||||
|
||||
@code{cpp}
|
||||
CEREAL_CLASS_VERSION( Mytype, 77 ); // register class version
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar, Mytype & t, const std::uint32_t version )
|
||||
{
|
||||
// When performing a load, the version associated with the class
|
||||
// is whatever it was when that data was originally serialized
|
||||
//
|
||||
// When we save, we'll use the version that is defined in the macro
|
||||
|
||||
if( version >= some_number )
|
||||
// do this
|
||||
else
|
||||
// do that
|
||||
}
|
||||
@endcode
|
||||
|
||||
Interfaces for other forms of serialization functions is similar. This
|
||||
macro should be placed at global scope.
|
||||
@ingroup Utility */
|
||||
#define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER) \
|
||||
namespace cereal { namespace detail { \
|
||||
template <> struct Version<TYPE> \
|
||||
{ \
|
||||
static const std::uint32_t version; \
|
||||
static std::uint32_t registerVersion() \
|
||||
{ \
|
||||
::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
|
||||
std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \
|
||||
return VERSION_NUMBER; \
|
||||
} \
|
||||
static void unused() { (void)version; } \
|
||||
}; /* end Version */ \
|
||||
const std::uint32_t Version<TYPE>::version = \
|
||||
Version<TYPE>::registerVersion(); \
|
||||
} } // end namespaces
|
||||
|
||||
// ######################################################################
|
||||
//! The base output archive class
|
||||
/*! This is the base output archive for all output archives. If you create
|
||||
a custom archive class, it should derive from this, passing itself as
|
||||
a template parameter for the ArchiveType.
|
||||
|
||||
The base class provides all of the functionality necessary to
|
||||
properly forward data to the correct serialization functions.
|
||||
|
||||
Individual archives should use a combination of prologue and
|
||||
epilogue functions together with specializations of serialize, save,
|
||||
and load to alter the functionality of their serialization.
|
||||
|
||||
@tparam ArchiveType The archive type that derives from OutputArchive
|
||||
@tparam Flags Flags to control advanced functionality. See the Flags
|
||||
enum for more information.
|
||||
@ingroup Internal */
|
||||
template<class ArchiveType, std::uint32_t Flags = 0>
|
||||
class OutputArchive : public detail::OutputArchiveBase
|
||||
{
|
||||
public:
|
||||
//! Construct the output archive
|
||||
/*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
|
||||
OutputArchive(ArchiveType * const derived) : self(derived), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
|
||||
{ }
|
||||
|
||||
OutputArchive & operator=( OutputArchive const & ) = delete;
|
||||
|
||||
//! Serializes all passed in data
|
||||
/*! This is the primary interface for serializing data with an archive */
|
||||
template <class ... Types> inline
|
||||
ArchiveType & operator()( Types && ... args )
|
||||
{
|
||||
self->process( std::forward<Types>( args )... );
|
||||
return *self;
|
||||
}
|
||||
|
||||
/*! @name Boost Transition Layer
|
||||
Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
|
||||
a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
|
||||
//! @{
|
||||
|
||||
//! Serializes passed in data
|
||||
/*! This is a boost compatability layer and is not the preferred way of using
|
||||
cereal. If you are transitioning from boost, use this until you can
|
||||
transition to the operator() overload */
|
||||
template <class T> inline
|
||||
ArchiveType & operator&( T && arg )
|
||||
{
|
||||
self->process( std::forward<T>( arg ) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Serializes passed in data
|
||||
/*! This is a boost compatability layer and is not the preferred way of using
|
||||
cereal. If you are transitioning from boost, use this until you can
|
||||
transition to the operator() overload */
|
||||
template <class T> inline
|
||||
ArchiveType & operator<<( T && arg )
|
||||
{
|
||||
self->process( std::forward<T>( arg ) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! @}
|
||||
|
||||
//! Registers a shared pointer with the archive
|
||||
/*! This function is used to track shared pointer targets to prevent
|
||||
unnecessary saves from taking place if multiple shared pointers
|
||||
point to the same data.
|
||||
|
||||
@internal
|
||||
@param addr The address (see shared_ptr get()) pointed to by the shared pointer
|
||||
@return A key that uniquely identifies the pointer */
|
||||
inline std::uint32_t registerSharedPointer( void const * addr )
|
||||
{
|
||||
// Handle null pointers by just returning 0
|
||||
if(addr == 0) return 0;
|
||||
|
||||
auto id = itsSharedPointerMap.find( addr );
|
||||
if( id == itsSharedPointerMap.end() )
|
||||
{
|
||||
auto ptrId = itsCurrentPointerId++;
|
||||
itsSharedPointerMap.insert( {addr, ptrId} );
|
||||
return ptrId | detail::msb_32bit; // mask MSB to be 1
|
||||
}
|
||||
else
|
||||
return id->second;
|
||||
}
|
||||
|
||||
//! Registers a polymorphic type name with the archive
|
||||
/*! This function is used to track polymorphic types to prevent
|
||||
unnecessary saves of identifying strings used by the polymorphic
|
||||
support functionality.
|
||||
|
||||
@internal
|
||||
@param name The name to associate with a polymorphic type
|
||||
@return A key that uniquely identifies the polymorphic type name */
|
||||
inline std::uint32_t registerPolymorphicType( char const * name )
|
||||
{
|
||||
auto id = itsPolymorphicTypeMap.find( name );
|
||||
if( id == itsPolymorphicTypeMap.end() )
|
||||
{
|
||||
auto polyId = itsCurrentPolymorphicTypeId++;
|
||||
itsPolymorphicTypeMap.insert( {name, polyId} );
|
||||
return polyId | detail::msb_32bit; // mask MSB to be 1
|
||||
}
|
||||
else
|
||||
return id->second;
|
||||
}
|
||||
|
||||
private:
|
||||
//! Serializes data after calling prologue, then calls epilogue
|
||||
template <class T> inline
|
||||
void process( T && head )
|
||||
{
|
||||
prologue( *self, head );
|
||||
self->processImpl( head );
|
||||
epilogue( *self, head );
|
||||
}
|
||||
|
||||
//! Unwinds to process all data
|
||||
template <class T, class ... Other> inline
|
||||
void process( T && head, Other && ... tail )
|
||||
{
|
||||
self->process( std::forward<T>( head ) );
|
||||
self->process( std::forward<Other>( tail )... );
|
||||
}
|
||||
|
||||
//! Serialization of a virtual_base_class wrapper
|
||||
/*! \sa virtual_base_class */
|
||||
template <class T> inline
|
||||
ArchiveType & processImpl(virtual_base_class<T> const & b)
|
||||
{
|
||||
traits::detail::base_class_id id(b.base_ptr);
|
||||
if(itsBaseClassSet.count(id) == 0)
|
||||
{
|
||||
itsBaseClassSet.insert(id);
|
||||
self->processImpl( *b.base_ptr );
|
||||
}
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Serialization of a base_class wrapper
|
||||
/*! \sa base_class */
|
||||
template <class T> inline
|
||||
ArchiveType & processImpl(base_class<T> const & b)
|
||||
{
|
||||
self->processImpl( *b.base_ptr );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Helper macro that expands the requirements for activating an overload
|
||||
/*! Requirements:
|
||||
Has the requested serialization function
|
||||
Does not have version and unversioned at the same time
|
||||
Is output serializable AND
|
||||
is specialized for this type of function OR
|
||||
has no specialization at all */
|
||||
#define PROCESS_IF(name) \
|
||||
traits::EnableIf<traits::has_##name<T, ArchiveType>::value, \
|
||||
!traits::has_invalid_output_versioning<T, ArchiveType>::value, \
|
||||
(traits::is_output_serializable<T, ArchiveType>::value && \
|
||||
(traits::is_specialized_##name<T, ArchiveType>::value || \
|
||||
!traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
|
||||
|
||||
//! Member serialization
|
||||
template <class T, PROCESS_IF(member_serialize)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
access::member_serialize(*self, const_cast<T &>(t));
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member serialization
|
||||
template <class T, PROCESS_IF(non_member_serialize)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t));
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (save)
|
||||
template <class T, PROCESS_IF(member_save)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
access::member_save(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (save)
|
||||
template <class T, PROCESS_IF(non_member_save)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
CEREAL_SAVE_FUNCTION_NAME(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (save_minimal)
|
||||
template <class T, PROCESS_IF(member_save_minimal)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
self->process( access::member_save_minimal(*self, t) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (save_minimal)
|
||||
template <class T, PROCESS_IF(non_member_save_minimal)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Empty class specialization
|
||||
template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
|
||||
!traits::is_output_serializable<T, ArchiveType>::value,
|
||||
std::is_empty<T>::value> = traits::sfinae> inline
|
||||
ArchiveType & processImpl(T const &)
|
||||
{
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! No matching serialization
|
||||
/*! Invalid if we have invalid output versioning or
|
||||
we are not output serializable, and either
|
||||
don't allow empty class ellision or allow it but are not serializing an empty class */
|
||||
template <class T, traits::EnableIf<traits::has_invalid_output_versioning<T, ArchiveType>::value ||
|
||||
(!traits::is_output_serializable<T, ArchiveType>::value &&
|
||||
(!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
|
||||
ArchiveType & processImpl(T const &)
|
||||
{
|
||||
static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value != 0,
|
||||
"cereal could not find any output serialization functions for the provided type and archive combination. \n\n "
|
||||
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
|
||||
"Serialize functions generally have the following signature: \n\n "
|
||||
"template<class Archive> \n "
|
||||
" void serialize(Archive & ar) \n "
|
||||
" { \n "
|
||||
" ar( member1, member2, member3 ); \n "
|
||||
" } \n\n " );
|
||||
|
||||
static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value < 2,
|
||||
"cereal found more than one compatible output serialization function for the provided type and archive combination. \n\n "
|
||||
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
|
||||
"Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
|
||||
"Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
|
||||
"In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
|
||||
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Registers a class version with the archive and serializes it if necessary
|
||||
/*! If this is the first time this class has been serialized, we will record its
|
||||
version number and serialize that.
|
||||
|
||||
@tparam T The type of the class being serialized
|
||||
@param version The version number associated with it */
|
||||
template <class T> inline
|
||||
std::uint32_t registerClassVersion()
|
||||
{
|
||||
static const auto hash = std::type_index(typeid(T)).hash_code();
|
||||
const auto insertResult = itsVersionedTypes.insert( hash );
|
||||
const auto version =
|
||||
detail::StaticObject<detail::Versions>::getInstance().find( hash, detail::Version<T>::version );
|
||||
|
||||
if( insertResult.second ) // insertion took place, serialize the version number
|
||||
process( make_nvp<ArchiveType>("cereal_class_version", version) );
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
//! Member serialization
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_serialize)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
access::member_serialize(*self, const_cast<T &>(t), registerClassVersion<T>());
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member serialization
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t), registerClassVersion<T>());
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (save)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_save)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
access::member_save(*self, t, registerClassVersion<T>());
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (save)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_save)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
CEREAL_SAVE_FUNCTION_NAME(*self, t, registerClassVersion<T>());
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (save_minimal)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_save_minimal)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
self->process( access::member_save_minimal(*self, t, registerClassVersion<T>()) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (save_minimal)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_save_minimal)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t, registerClassVersion<T>()) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
#undef PROCESS_IF
|
||||
|
||||
private:
|
||||
ArchiveType * const self;
|
||||
|
||||
//! A set of all base classes that have been serialized
|
||||
std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
|
||||
|
||||
//! Maps from addresses to pointer ids
|
||||
std::unordered_map<void const *, std::uint32_t> itsSharedPointerMap;
|
||||
|
||||
//! The id to be given to the next pointer
|
||||
std::uint32_t itsCurrentPointerId;
|
||||
|
||||
//! Maps from polymorphic type name strings to ids
|
||||
std::unordered_map<char const *, std::uint32_t> itsPolymorphicTypeMap;
|
||||
|
||||
//! The id to be given to the next polymorphic type name
|
||||
std::uint32_t itsCurrentPolymorphicTypeId;
|
||||
|
||||
//! Keeps track of classes that have versioning information associated with them
|
||||
std::unordered_set<size_type> itsVersionedTypes;
|
||||
}; // class OutputArchive
|
||||
|
||||
// ######################################################################
|
||||
//! The base input archive class
|
||||
/*! This is the base input archive for all input archives. If you create
|
||||
a custom archive class, it should derive from this, passing itself as
|
||||
a template parameter for the ArchiveType.
|
||||
|
||||
The base class provides all of the functionality necessary to
|
||||
properly forward data to the correct serialization functions.
|
||||
|
||||
Individual archives should use a combination of prologue and
|
||||
epilogue functions together with specializations of serialize, save,
|
||||
and load to alter the functionality of their serialization.
|
||||
|
||||
@tparam ArchiveType The archive type that derives from InputArchive
|
||||
@tparam Flags Flags to control advanced functionality. See the Flags
|
||||
enum for more information.
|
||||
@ingroup Internal */
|
||||
template<class ArchiveType, std::uint32_t Flags = 0>
|
||||
class InputArchive : public detail::InputArchiveBase
|
||||
{
|
||||
public:
|
||||
//! Construct the output archive
|
||||
/*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
|
||||
InputArchive(ArchiveType * const derived) :
|
||||
self(derived),
|
||||
itsBaseClassSet(),
|
||||
itsSharedPointerMap(),
|
||||
itsPolymorphicTypeMap(),
|
||||
itsVersionedTypes()
|
||||
{ }
|
||||
|
||||
InputArchive & operator=( InputArchive const & ) = delete;
|
||||
|
||||
//! Serializes all passed in data
|
||||
/*! This is the primary interface for serializing data with an archive */
|
||||
template <class ... Types> inline
|
||||
ArchiveType & operator()( Types && ... args )
|
||||
{
|
||||
process( std::forward<Types>( args )... );
|
||||
return *self;
|
||||
}
|
||||
|
||||
/*! @name Boost Transition Layer
|
||||
Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
|
||||
a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
|
||||
//! @{
|
||||
|
||||
//! Serializes passed in data
|
||||
/*! This is a boost compatability layer and is not the preferred way of using
|
||||
cereal. If you are transitioning from boost, use this until you can
|
||||
transition to the operator() overload */
|
||||
template <class T> inline
|
||||
ArchiveType & operator&( T && arg )
|
||||
{
|
||||
self->process( std::forward<T>( arg ) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Serializes passed in data
|
||||
/*! This is a boost compatability layer and is not the preferred way of using
|
||||
cereal. If you are transitioning from boost, use this until you can
|
||||
transition to the operator() overload */
|
||||
template <class T> inline
|
||||
ArchiveType & operator>>( T && arg )
|
||||
{
|
||||
self->process( std::forward<T>( arg ) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! @}
|
||||
|
||||
//! Retrieves a shared pointer given a unique key for it
|
||||
/*! This is used to retrieve a previously registered shared_ptr
|
||||
which has already been loaded.
|
||||
|
||||
@param id The unique id that was serialized for the pointer
|
||||
@return A shared pointer to the data
|
||||
@throw Exception if the id does not exist */
|
||||
inline std::shared_ptr<void> getSharedPointer(std::uint32_t const id)
|
||||
{
|
||||
if(id == 0) return std::shared_ptr<void>(nullptr);
|
||||
|
||||
auto iter = itsSharedPointerMap.find( id );
|
||||
if(iter == itsSharedPointerMap.end())
|
||||
throw Exception("Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(id));
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
//! Registers a shared pointer to its unique identifier
|
||||
/*! After a shared pointer has been allocated for the first time, it should
|
||||
be registered with its loaded id for future references to it.
|
||||
|
||||
@param id The unique identifier for the shared pointer
|
||||
@param ptr The actual shared pointer */
|
||||
inline void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
|
||||
{
|
||||
std::uint32_t const stripped_id = id & ~detail::msb_32bit;
|
||||
itsSharedPointerMap[stripped_id] = ptr;
|
||||
}
|
||||
|
||||
//! Retrieves the string for a polymorphic type given a unique key for it
|
||||
/*! This is used to retrieve a string previously registered during
|
||||
a polymorphic load.
|
||||
|
||||
@param id The unique id that was serialized for the polymorphic type
|
||||
@return The string identifier for the tyep */
|
||||
inline std::string getPolymorphicName(std::uint32_t const id)
|
||||
{
|
||||
auto name = itsPolymorphicTypeMap.find( id );
|
||||
if(name == itsPolymorphicTypeMap.end())
|
||||
{
|
||||
throw Exception("Error while trying to deserialize a polymorphic pointer. Could not find type id " + std::to_string(id));
|
||||
}
|
||||
return name->second;
|
||||
}
|
||||
|
||||
//! Registers a polymorphic name string to its unique identifier
|
||||
/*! After a polymorphic type has been loaded for the first time, it should
|
||||
be registered with its loaded id for future references to it.
|
||||
|
||||
@param id The unique identifier for the polymorphic type
|
||||
@param name The name associated with the tyep */
|
||||
inline void registerPolymorphicName(std::uint32_t const id, std::string const & name)
|
||||
{
|
||||
std::uint32_t const stripped_id = id & ~detail::msb_32bit;
|
||||
itsPolymorphicTypeMap.insert( {stripped_id, name} );
|
||||
}
|
||||
|
||||
private:
|
||||
//! Serializes data after calling prologue, then calls epilogue
|
||||
template <class T> inline
|
||||
void process( T && head )
|
||||
{
|
||||
prologue( *self, head );
|
||||
self->processImpl( head );
|
||||
epilogue( *self, head );
|
||||
}
|
||||
|
||||
//! Unwinds to process all data
|
||||
template <class T, class ... Other> inline
|
||||
void process( T && head, Other && ... tail )
|
||||
{
|
||||
process( std::forward<T>( head ) );
|
||||
process( std::forward<Other>( tail )... );
|
||||
}
|
||||
|
||||
//! Serialization of a virtual_base_class wrapper
|
||||
/*! \sa virtual_base_class */
|
||||
template <class T> inline
|
||||
ArchiveType & processImpl(virtual_base_class<T> & b)
|
||||
{
|
||||
traits::detail::base_class_id id(b.base_ptr);
|
||||
if(itsBaseClassSet.count(id) == 0)
|
||||
{
|
||||
itsBaseClassSet.insert(id);
|
||||
self->processImpl( *b.base_ptr );
|
||||
}
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Serialization of a base_class wrapper
|
||||
/*! \sa base_class */
|
||||
template <class T> inline
|
||||
ArchiveType & processImpl(base_class<T> & b)
|
||||
{
|
||||
self->processImpl( *b.base_ptr );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Helper macro that expands the requirements for activating an overload
|
||||
/*! Requirements:
|
||||
Has the requested serialization function
|
||||
Does not have version and unversioned at the same time
|
||||
Is input serializable AND
|
||||
is specialized for this type of function OR
|
||||
has no specialization at all */
|
||||
#define PROCESS_IF(name) \
|
||||
traits::EnableIf<traits::has_##name<T, ArchiveType>::value, \
|
||||
!traits::has_invalid_input_versioning<T, ArchiveType>::value, \
|
||||
(traits::is_input_serializable<T, ArchiveType>::value && \
|
||||
(traits::is_specialized_##name<T, ArchiveType>::value || \
|
||||
!traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
|
||||
|
||||
//! Member serialization
|
||||
template <class T, PROCESS_IF(member_serialize)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
access::member_serialize(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member serialization
|
||||
template <class T, PROCESS_IF(non_member_serialize)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (load)
|
||||
template <class T, PROCESS_IF(member_load)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
access::member_load(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (load)
|
||||
template <class T, PROCESS_IF(non_member_load)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
CEREAL_LOAD_FUNCTION_NAME(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (load_minimal)
|
||||
template <class T, PROCESS_IF(member_load_minimal)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||
typename traits::has_member_save_minimal<T, OutArchiveType>::type value;
|
||||
self->process( value );
|
||||
access::member_load_minimal(*self, t, value);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (load_minimal)
|
||||
template <class T, PROCESS_IF(non_member_load_minimal)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||
typename traits::has_non_member_save_minimal<T, OutArchiveType>::type value;
|
||||
self->process( value );
|
||||
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Empty class specialization
|
||||
template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
|
||||
!traits::is_input_serializable<T, ArchiveType>::value,
|
||||
std::is_empty<T>::value> = traits::sfinae> inline
|
||||
ArchiveType & processImpl(T const &)
|
||||
{
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! No matching serialization
|
||||
/*! Invalid if we have invalid input versioning or
|
||||
we are not input serializable, and either
|
||||
don't allow empty class ellision or allow it but are not serializing an empty class */
|
||||
template <class T, traits::EnableIf<traits::has_invalid_input_versioning<T, ArchiveType>::value ||
|
||||
(!traits::is_input_serializable<T, ArchiveType>::value &&
|
||||
(!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
|
||||
ArchiveType & processImpl(T const &)
|
||||
{
|
||||
static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value != 0,
|
||||
"cereal could not find any input serialization functions for the provided type and archive combination. \n\n "
|
||||
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
|
||||
"Serialize functions generally have the following signature: \n\n "
|
||||
"template<class Archive> \n "
|
||||
" void serialize(Archive & ar) \n "
|
||||
" { \n "
|
||||
" ar( member1, member2, member3 ); \n "
|
||||
" } \n\n " );
|
||||
|
||||
static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value < 2,
|
||||
"cereal found more than one compatible input serialization function for the provided type and archive combination. \n\n "
|
||||
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
|
||||
"Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
|
||||
"Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
|
||||
"In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
|
||||
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Registers a class version with the archive and serializes it if necessary
|
||||
/*! If this is the first time this class has been serialized, we will record its
|
||||
version number and serialize that.
|
||||
|
||||
@tparam T The type of the class being serialized
|
||||
@param version The version number associated with it */
|
||||
template <class T> inline
|
||||
std::uint32_t loadClassVersion()
|
||||
{
|
||||
static const auto hash = std::type_index(typeid(T)).hash_code();
|
||||
auto lookupResult = itsVersionedTypes.find( hash );
|
||||
|
||||
if( lookupResult != itsVersionedTypes.end() ) // already exists
|
||||
return lookupResult->second;
|
||||
else // need to load
|
||||
{
|
||||
std::uint32_t version;
|
||||
|
||||
process( make_nvp<ArchiveType>("cereal_class_version", version) );
|
||||
itsVersionedTypes.emplace_hint( lookupResult, hash, version );
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
//! Member serialization
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_serialize)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
const auto version = loadClassVersion<T>();
|
||||
access::member_serialize(*self, t, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member serialization
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
const auto version = loadClassVersion<T>();
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME(*self, t, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (load)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_load)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
const auto version = loadClassVersion<T>();
|
||||
access::member_load(*self, t, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (load)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_load)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
const auto version = loadClassVersion<T>();
|
||||
CEREAL_LOAD_FUNCTION_NAME(*self, t, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (load_minimal)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_load_minimal)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||
const auto version = loadClassVersion<T>();
|
||||
typename traits::has_member_versioned_save_minimal<T, OutArchiveType>::type value;
|
||||
self->process(value);
|
||||
access::member_load_minimal(*self, t, value, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (load_minimal)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_load_minimal)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||
const auto version = loadClassVersion<T>();
|
||||
typename traits::has_non_member_versioned_save_minimal<T, OutArchiveType>::type value;
|
||||
self->process(value);
|
||||
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
#undef PROCESS_IF
|
||||
|
||||
private:
|
||||
ArchiveType * const self;
|
||||
|
||||
//! A set of all base classes that have been serialized
|
||||
std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
|
||||
|
||||
//! Maps from pointer ids to metadata
|
||||
std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
|
||||
|
||||
//! Maps from name ids to names
|
||||
std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
|
||||
|
||||
//! Maps from type hash codes to version numbers
|
||||
std::unordered_map<std::size_t, std::uint32_t> itsVersionedTypes;
|
||||
}; // class InputArchive
|
||||
} // namespace cereal
|
||||
|
||||
// This include needs to come after things such as binary_data, make_nvp, etc
|
||||
#include <cereal/types/common.hpp>
|
||||
|
||||
#endif // CEREAL_CEREAL_HPP_
|
||||
360
libs/cereal/cereal/details/helpers.hpp
Normal file
360
libs/cereal/cereal/details/helpers.hpp
Normal file
@ -0,0 +1,360 @@
|
||||
/*! \file helpers.hpp
|
||||
\brief Internal helper functionality
|
||||
\ingroup Internal */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_DETAILS_HELPERS_HPP_
|
||||
#define CEREAL_DETAILS_HELPERS_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cereal/macros.hpp>
|
||||
#include <cereal/details/static_object.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// ######################################################################
|
||||
//! An exception class thrown when things go wrong at runtime
|
||||
/*! @ingroup Utility */
|
||||
struct Exception : public std::runtime_error
|
||||
{
|
||||
explicit Exception( const std::string & what_ ) : std::runtime_error(what_) {}
|
||||
explicit Exception( const char * what_ ) : std::runtime_error(what_) {}
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
//! The size type used by cereal
|
||||
/*! To ensure compatability between 32, 64, etc bit machines, we need to use
|
||||
a fixed size type instead of size_t, which may vary from machine to
|
||||
machine. */
|
||||
using size_type = uint64_t;
|
||||
|
||||
// forward decls
|
||||
class BinaryOutputArchive;
|
||||
class BinaryInputArchive;
|
||||
|
||||
// ######################################################################
|
||||
namespace detail
|
||||
{
|
||||
struct NameValuePairCore {}; //!< Traits struct for NVPs
|
||||
}
|
||||
|
||||
//! For holding name value pairs
|
||||
/*! This pairs a name (some string) with some value such that an archive
|
||||
can potentially take advantage of the pairing.
|
||||
|
||||
In serialization functions, NameValuePairs are usually created like so:
|
||||
@code{.cpp}
|
||||
struct MyStruct
|
||||
{
|
||||
int a, b, c, d, e;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive( CEREAL_NVP(a),
|
||||
CEREAL_NVP(b),
|
||||
CEREAL_NVP(c),
|
||||
CEREAL_NVP(d),
|
||||
CEREAL_NVP(e) );
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
Alternatively, you can give you data members custom names like so:
|
||||
@code{.cpp}
|
||||
struct MyStruct
|
||||
{
|
||||
int a, b, my_embarrassing_variable_name, d, e;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive( CEREAL_NVP(a),
|
||||
CEREAL_NVP(b),
|
||||
cereal::make_nvp("var", my_embarrassing_variable_name) );
|
||||
CEREAL_NVP(d),
|
||||
CEREAL_NVP(e) );
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
There is a slight amount of overhead to creating NameValuePairs, so there
|
||||
is a third method which will elide the names when they are not used by
|
||||
the Archive:
|
||||
|
||||
@code{.cpp}
|
||||
struct MyStruct
|
||||
{
|
||||
int a, b;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive( cereal::make_nvp<Archive>(a),
|
||||
cereal::make_nvp<Archive>(b) );
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
This third method is generally only used when providing generic type
|
||||
support. Users writing their own serialize functions will normally
|
||||
explicitly control whether they want to use NVPs or not.
|
||||
|
||||
@internal */
|
||||
template <class T>
|
||||
class NameValuePair : detail::NameValuePairCore
|
||||
{
|
||||
private:
|
||||
// If we get passed an array, keep the type as is, otherwise store
|
||||
// a reference if we were passed an l value reference, else copy the value
|
||||
using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
|
||||
typename std::remove_cv<T>::type,
|
||||
typename std::conditional<std::is_lvalue_reference<T>::value,
|
||||
T,
|
||||
typename std::decay<T>::type>::type>::type;
|
||||
|
||||
// prevent nested nvps
|
||||
static_assert( !std::is_base_of<detail::NameValuePairCore, T>::value,
|
||||
"Cannot pair a name to a NameValuePair" );
|
||||
|
||||
NameValuePair & operator=( NameValuePair const & ) = delete;
|
||||
|
||||
public:
|
||||
//! Constructs a new NameValuePair
|
||||
/*! @param n The name of the pair
|
||||
@param v The value to pair. Ideally this should be an l-value reference so that
|
||||
the value can be both loaded and saved to. If you pass an r-value reference,
|
||||
the NameValuePair will store a copy of it instead of a reference. Thus you should
|
||||
only pass r-values in cases where this makes sense, such as the result of some
|
||||
size() call.
|
||||
@internal */
|
||||
NameValuePair( char const * n, T && v ) : name(n), value(std::forward<T>(v)) {}
|
||||
|
||||
char const * name;
|
||||
Type value;
|
||||
};
|
||||
|
||||
//! A specialization of make_nvp<> that simply forwards the value for binary archives
|
||||
/*! @relates NameValuePair
|
||||
@internal */
|
||||
template<class Archive, class T> inline
|
||||
typename
|
||||
std::enable_if<std::is_same<Archive, ::cereal::BinaryInputArchive>::value ||
|
||||
std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
|
||||
T && >::type
|
||||
make_nvp( const char *, T && value )
|
||||
{
|
||||
return std::forward<T>(value);
|
||||
}
|
||||
|
||||
//! A specialization of make_nvp<> that actually creates an nvp for non-binary archives
|
||||
/*! @relates NameValuePair
|
||||
@internal */
|
||||
template<class Archive, class T> inline
|
||||
typename
|
||||
std::enable_if<!std::is_same<Archive, ::cereal::BinaryInputArchive>::value &&
|
||||
!std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
|
||||
NameValuePair<T> >::type
|
||||
make_nvp( const char * name, T && value)
|
||||
{
|
||||
return {name, std::forward<T>(value)};
|
||||
}
|
||||
|
||||
//! Convenience for creating a templated NVP
|
||||
/*! For use in inteneral generic typing functions which have an
|
||||
Archive type declared
|
||||
@internal */
|
||||
#define CEREAL_NVP_(name, value) ::cereal::make_nvp<Archive>(name, value)
|
||||
|
||||
// ######################################################################
|
||||
//! A wrapper around data that can be serialized in a binary fashion
|
||||
/*! This class is used to demarcate data that can safely be serialized
|
||||
as a binary chunk of data. Individual archives can then choose how
|
||||
best represent this during serialization.
|
||||
|
||||
@internal */
|
||||
template <class T>
|
||||
struct BinaryData
|
||||
{
|
||||
//! Internally store the pointer as a void *, keeping const if created with
|
||||
//! a const pointer
|
||||
using PT = typename std::conditional<std::is_const<typename std::remove_pointer<T>::type>::value,
|
||||
const void *,
|
||||
void *>::type;
|
||||
|
||||
BinaryData( T && d, uint64_t s ) : data(std::forward<T>(d)), size(s) {}
|
||||
|
||||
PT data; //!< pointer to beginning of data
|
||||
uint64_t size; //!< size in bytes
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
namespace detail
|
||||
{
|
||||
// base classes for type checking
|
||||
/* The rtti virtual function only exists to enable an archive to
|
||||
be used in a polymorphic fashion, if necessary. See the
|
||||
archive adapters for an example of this */
|
||||
class OutputArchiveBase { private: virtual void rtti(){} };
|
||||
class InputArchiveBase { private: virtual void rtti(){} };
|
||||
|
||||
// forward decls for polymorphic support
|
||||
template <class Archive, class T> struct polymorphic_serialization_support;
|
||||
struct adl_tag;
|
||||
|
||||
// used during saving pointers
|
||||
static const int32_t msb_32bit = 0x80000000;
|
||||
static const int32_t msb2_32bit = 0x40000000;
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! A wrapper around size metadata
|
||||
/*! This class provides a way for archives to have more flexibility over how
|
||||
they choose to serialize size metadata for containers. For some archive
|
||||
types, the size may be implicitly encoded in the output (e.g. JSON) and
|
||||
not need an explicit entry. Specializing serialize or load/save for
|
||||
your archive and SizeTags allows you to choose what happens.
|
||||
|
||||
@internal */
|
||||
template <class T>
|
||||
class SizeTag
|
||||
{
|
||||
private:
|
||||
// Store a reference if passed an lvalue reference, otherwise
|
||||
// make a copy of the data
|
||||
using Type = typename std::conditional<std::is_lvalue_reference<T>::value,
|
||||
T,
|
||||
typename std::decay<T>::type>::type;
|
||||
|
||||
SizeTag & operator=( SizeTag const & ) = delete;
|
||||
|
||||
public:
|
||||
SizeTag( T && sz ) : size(std::forward<T>(sz)) {}
|
||||
|
||||
Type size;
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
//! A wrapper around a key and value for serializing data into maps.
|
||||
/*! This class just provides a grouping of keys and values into a struct for
|
||||
human readable archives. For example, XML archives will use this wrapper
|
||||
to write maps like so:
|
||||
|
||||
@code{.xml}
|
||||
<mymap>
|
||||
<item0>
|
||||
<key>MyFirstKey</key>
|
||||
<value>MyFirstValue</value>
|
||||
</item0>
|
||||
<item1>
|
||||
<key>MySecondKey</key>
|
||||
<value>MySecondValue</value>
|
||||
</item1>
|
||||
</mymap>
|
||||
@endcode
|
||||
|
||||
\sa make_map_item
|
||||
@internal */
|
||||
template <class Key, class Value>
|
||||
struct MapItem
|
||||
{
|
||||
using KeyType = typename std::conditional<
|
||||
std::is_lvalue_reference<Key>::value,
|
||||
Key,
|
||||
typename std::decay<Key>::type>::type;
|
||||
|
||||
using ValueType = typename std::conditional<
|
||||
std::is_lvalue_reference<Value>::value,
|
||||
Value,
|
||||
typename std::decay<Value>::type>::type;
|
||||
|
||||
//! Construct a MapItem from a key and a value
|
||||
/*! @internal */
|
||||
MapItem( Key && key_, Value && value_ ) : key(std::forward<Key>(key_)), value(std::forward<Value>(value_)) {}
|
||||
|
||||
MapItem & operator=( MapItem const & ) = delete;
|
||||
|
||||
KeyType key;
|
||||
ValueType value;
|
||||
|
||||
//! Serialize the MapItem with the NVPs "key" and "value"
|
||||
template <class Archive> inline
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME(Archive & archive)
|
||||
{
|
||||
archive( make_nvp<Archive>("key", key),
|
||||
make_nvp<Archive>("value", value) );
|
||||
}
|
||||
};
|
||||
|
||||
//! Create a MapItem so that human readable archives will group keys and values together
|
||||
/*! @internal
|
||||
@relates MapItem */
|
||||
template <class KeyType, class ValueType> inline
|
||||
MapItem<KeyType, ValueType> make_map_item(KeyType && key, ValueType && value)
|
||||
{
|
||||
return {std::forward<KeyType>(key), std::forward<ValueType>(value)};
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//! Tag for Version, which due to its anonymous namespace, becomes a different
|
||||
//! type in each translation unit
|
||||
/*! This allows CEREAL_CLASS_VERSION to be safely called in a header file */
|
||||
namespace{ struct version_binding_tag {}; }
|
||||
|
||||
// ######################################################################
|
||||
//! Version information class
|
||||
/*! This is the base case for classes that have not been explicitly
|
||||
registered */
|
||||
template <class T, class BindingTag = version_binding_tag> struct Version
|
||||
{
|
||||
static const std::uint32_t version = 0;
|
||||
// we don't need to explicitly register these types since they
|
||||
// always get a version number of 0
|
||||
};
|
||||
|
||||
//! Holds all registered version information
|
||||
struct Versions
|
||||
{
|
||||
std::unordered_map<std::size_t, std::uint32_t> mapping;
|
||||
|
||||
std::uint32_t find( std::size_t hash, std::uint32_t version )
|
||||
{
|
||||
const auto result = mapping.emplace( hash, version );
|
||||
return result.first->second;
|
||||
}
|
||||
}; // struct Versions
|
||||
} // namespace detail
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_DETAILS_HELPERS_HPP_
|
||||
437
libs/cereal/cereal/details/polymorphic_impl.hpp
Normal file
437
libs/cereal/cereal/details/polymorphic_impl.hpp
Normal file
@ -0,0 +1,437 @@
|
||||
/*! \file polymorphic_impl.hpp
|
||||
\brief Internal polymorphism support
|
||||
\ingroup Internal */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
|
||||
/* This code is heavily inspired by the boost serialization implementation by the following authors
|
||||
|
||||
(C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
|
||||
Use, modification and distribution is subject to the Boost Software
|
||||
License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
See http://www.boost.org for updates, documentation, and revision history.
|
||||
|
||||
(C) Copyright 2006 David Abrahams - http://www.boost.org.
|
||||
|
||||
See /boost/serialization/export.hpp and /boost/archive/detail/register_archive.hpp for their
|
||||
implementation.
|
||||
*/
|
||||
#ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
|
||||
#define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
|
||||
|
||||
#include <cereal/details/static_object.hpp>
|
||||
#include <cereal/types/memory.hpp>
|
||||
#include <cereal/types/string.hpp>
|
||||
#include <functional>
|
||||
#include <typeindex>
|
||||
#include <map>
|
||||
|
||||
//! Binds a polymorhic type to all registered archives
|
||||
/*! This binds a polymorphic type to all compatible registered archives that
|
||||
have been registered with CEREAL_REGISTER_ARCHIVE. This must be called
|
||||
after all archives are registered (usually after the archives themselves
|
||||
have been included). */
|
||||
#define CEREAL_BIND_TO_ARCHIVES(T) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
template<> \
|
||||
struct init_binding<T> { \
|
||||
static bind_to_archives<T> const & b; \
|
||||
static void unused() { (void)b; } \
|
||||
}; \
|
||||
bind_to_archives<T> const & init_binding<T>::b = \
|
||||
::cereal::detail::StaticObject< \
|
||||
bind_to_archives<T> \
|
||||
>::getInstance().bind(); \
|
||||
}} /* end namespaces */
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
//! Binds a compile time type with a user defined string
|
||||
template <class T>
|
||||
struct binding_name {};
|
||||
|
||||
//! A structure holding a map from type_indices to output serializer functions
|
||||
/*! A static object of this map should be created for each registered archive
|
||||
type, containing entries for every registered type that describe how to
|
||||
properly cast the type to its real type in polymorphic scenarios for
|
||||
shared_ptr, weak_ptr, and unique_ptr. */
|
||||
template <class Archive>
|
||||
struct OutputBindingMap
|
||||
{
|
||||
//! A serializer function
|
||||
/*! Serializer functions return nothing and take an archive as
|
||||
their first parameter (will be cast properly inside the function,
|
||||
and a pointer to actual data (contents of smart_ptr's get() function)
|
||||
as their second parameter */
|
||||
typedef std::function<void(void*, void const *)> Serializer;
|
||||
|
||||
//! Struct containing the serializer functions for all pointer types
|
||||
struct Serializers
|
||||
{
|
||||
Serializer shared_ptr, //!< Serializer function for shared/weak pointers
|
||||
unique_ptr; //!< Serializer function for unique pointers
|
||||
};
|
||||
|
||||
//! A map of serializers for pointers of all registered types
|
||||
std::map<std::type_index, Serializers> map;
|
||||
};
|
||||
|
||||
//! An empty noop deleter
|
||||
template<class T> struct EmptyDeleter { void operator()(T *) const {} };
|
||||
|
||||
//! A structure holding a map from type name strings to input serializer functions
|
||||
/*! A static object of this map should be created for each registered archive
|
||||
type, containing entries for every registered type that describe how to
|
||||
properly cast the type to its real type in polymorphic scenarios for
|
||||
shared_ptr, weak_ptr, and unique_ptr. */
|
||||
template <class Archive>
|
||||
struct InputBindingMap
|
||||
{
|
||||
//! Shared ptr serializer function
|
||||
/*! Serializer functions return nothing and take an archive as
|
||||
their first parameter (will be cast properly inside the function,
|
||||
and a shared_ptr (or unique_ptr for the unique case) of any base
|
||||
type. Internally it will properly be loaded and cast to the
|
||||
correct type. */
|
||||
typedef std::function<void(void*, std::shared_ptr<void> & )> SharedSerializer;
|
||||
//! Unique ptr serializer function
|
||||
typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> & )> UniqueSerializer;
|
||||
|
||||
//! Struct containing the serializer functions for all pointer types
|
||||
struct Serializers
|
||||
{
|
||||
SharedSerializer shared_ptr; //!< Serializer function for shared/weak pointers
|
||||
UniqueSerializer unique_ptr; //!< Serializer function for unique pointers
|
||||
};
|
||||
|
||||
//! A map of serializers for pointers of all registered types
|
||||
std::map<std::string, Serializers> map;
|
||||
};
|
||||
|
||||
// forward decls for archives from cereal.hpp
|
||||
class InputArchiveBase;
|
||||
class OutputArchiveBase;
|
||||
|
||||
//! Creates a binding (map entry) between an input archive type and a polymorphic type
|
||||
/*! Bindings are made when types are registered, assuming that at least one
|
||||
archive has already been registered. When this struct is created,
|
||||
it will insert (at run time) an entry into a map that properly handles
|
||||
casting for serializing polymorphic objects */
|
||||
template <class Archive, class T> struct InputBindingCreator
|
||||
{
|
||||
//! Initialize the binding
|
||||
InputBindingCreator()
|
||||
{
|
||||
auto & map = StaticObject<InputBindingMap<Archive>>::getInstance().map;
|
||||
auto key = std::string(binding_name<T>::name());
|
||||
auto lb = map.lower_bound(key);
|
||||
|
||||
if (lb != map.end() && lb->first == key)
|
||||
return;
|
||||
|
||||
typename InputBindingMap<Archive>::Serializers serializers;
|
||||
|
||||
serializers.shared_ptr =
|
||||
[](void * arptr, std::shared_ptr<void> & dptr)
|
||||
{
|
||||
Archive & ar = *static_cast<Archive*>(arptr);
|
||||
std::shared_ptr<T> ptr;
|
||||
|
||||
ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
|
||||
|
||||
dptr = ptr;
|
||||
};
|
||||
|
||||
serializers.unique_ptr =
|
||||
[](void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr)
|
||||
{
|
||||
Archive & ar = *static_cast<Archive*>(arptr);
|
||||
std::unique_ptr<T> ptr;
|
||||
|
||||
ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
|
||||
|
||||
dptr.reset(ptr.release());
|
||||
};
|
||||
|
||||
map.insert( lb, { std::move(key), std::move(serializers) } );
|
||||
}
|
||||
};
|
||||
|
||||
//! Creates a binding (map entry) between an output archive type and a polymorphic type
|
||||
/*! Bindings are made when types are registered, assuming that at least one
|
||||
archive has already been registered. When this struct is created,
|
||||
it will insert (at run time) an entry into a map that properly handles
|
||||
casting for serializing polymorphic objects */
|
||||
template <class Archive, class T> struct OutputBindingCreator
|
||||
{
|
||||
//! Writes appropriate metadata to the archive for this polymorphic type
|
||||
static void writeMetadata(Archive & ar)
|
||||
{
|
||||
// Register the polymorphic type name with the archive, and get the id
|
||||
char const * name = binding_name<T>::name();
|
||||
std::uint32_t id = ar.registerPolymorphicType(name);
|
||||
|
||||
// Serialize the id
|
||||
ar( CEREAL_NVP_("polymorphic_id", id) );
|
||||
|
||||
// If the msb of the id is 1, then the type name is new, and we should serialize it
|
||||
if( id & detail::msb_32bit )
|
||||
{
|
||||
std::string namestring(name);
|
||||
ar( CEREAL_NVP_("polymorphic_name", namestring) );
|
||||
}
|
||||
}
|
||||
|
||||
//! Holds a properly typed shared_ptr to the polymorphic type
|
||||
class PolymorphicSharedPointerWrapper
|
||||
{
|
||||
public:
|
||||
/*! Wrap a raw polymorphic pointer in a shared_ptr to its true type
|
||||
|
||||
The wrapped pointer will not be responsible for ownership of the held pointer
|
||||
so it will not attempt to destroy it; instead the refcount of the wrapped
|
||||
pointer will be tied to a fake 'ownership pointer' that will do nothing
|
||||
when it ultimately goes out of scope.
|
||||
|
||||
The main reason for doing this, other than not to destroy the true object
|
||||
with our wrapper pointer, is to avoid meddling with the internal reference
|
||||
count in a polymorphic type that inherits from std::enable_shared_from_this.
|
||||
|
||||
@param dptr A void pointer to the contents of the shared_ptr to serialize */
|
||||
PolymorphicSharedPointerWrapper( void const * dptr ) : refCount()
|
||||
{
|
||||
#ifdef _LIBCPP_VERSION
|
||||
// libc++ needs this hacky workaround, see http://llvm.org/bugs/show_bug.cgi?id=18843
|
||||
wrappedPtr = std::shared_ptr<T const>(
|
||||
std::const_pointer_cast<T const>(
|
||||
std::shared_ptr<T>( refCount, static_cast<T *>(const_cast<void *>(dptr) ))));
|
||||
#else // NOT _LIBCPP_VERSION
|
||||
wrappedPtr = std::shared_ptr<T const>( refCount, static_cast<T const *>(dptr) );
|
||||
#endif // _LIBCPP_VERSION
|
||||
}
|
||||
|
||||
//! Get the wrapped shared_ptr */
|
||||
inline std::shared_ptr<T const> const & operator()() const { return wrappedPtr; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<void> refCount; //!< The ownership pointer
|
||||
std::shared_ptr<T const> wrappedPtr; //!< The wrapped pointer
|
||||
};
|
||||
|
||||
//! Does the actual work of saving a polymorphic shared_ptr
|
||||
/*! This function will properly create a shared_ptr from the void * that is passed in
|
||||
before passing it to the archive for serialization.
|
||||
|
||||
In addition, this will also preserve the state of any internal enable_shared_from_this mechanisms
|
||||
|
||||
@param ar The archive to serialize to
|
||||
@param dptr Pointer to the actual data held by the shared_ptr */
|
||||
static inline void savePolymorphicSharedPtr( Archive & ar, void const * dptr, std::true_type /* has_shared_from_this */ )
|
||||
{
|
||||
::cereal::memory_detail::EnableSharedStateHelper<T> state( static_cast<T *>(const_cast<void *>(dptr)) );
|
||||
PolymorphicSharedPointerWrapper psptr( dptr );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
|
||||
}
|
||||
|
||||
//! Does the actual work of saving a polymorphic shared_ptr
|
||||
/*! This function will properly create a shared_ptr from the void * that is passed in
|
||||
before passing it to the archive for serialization.
|
||||
|
||||
This version is for types that do not inherit from std::enable_shared_from_this.
|
||||
|
||||
@param ar The archive to serialize to
|
||||
@param dptr Pointer to the actual data held by the shared_ptr */
|
||||
static inline void savePolymorphicSharedPtr( Archive & ar, void const * dptr, std::false_type /* has_shared_from_this */ )
|
||||
{
|
||||
PolymorphicSharedPointerWrapper psptr( dptr );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
|
||||
}
|
||||
|
||||
//! Initialize the binding
|
||||
OutputBindingCreator()
|
||||
{
|
||||
auto & map = StaticObject<OutputBindingMap<Archive>>::getInstance().map;
|
||||
auto key = std::type_index(typeid(T));
|
||||
auto lb = map.lower_bound(key);
|
||||
|
||||
if (lb != map.end() && lb->first == key)
|
||||
return;
|
||||
|
||||
typename OutputBindingMap<Archive>::Serializers serializers;
|
||||
|
||||
serializers.shared_ptr =
|
||||
[&](void * arptr, void const * dptr)
|
||||
{
|
||||
Archive & ar = *static_cast<Archive*>(arptr);
|
||||
|
||||
writeMetadata(ar);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
savePolymorphicSharedPtr( ar, dptr, ::cereal::traits::has_shared_from_this<T>::type() ); // MSVC doesn't like typename here
|
||||
#else // not _MSC_VER
|
||||
savePolymorphicSharedPtr( ar, dptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
|
||||
#endif // _MSC_VER
|
||||
};
|
||||
|
||||
serializers.unique_ptr =
|
||||
[&](void * arptr, void const * dptr)
|
||||
{
|
||||
Archive & ar = *static_cast<Archive*>(arptr);
|
||||
|
||||
writeMetadata(ar);
|
||||
|
||||
std::unique_ptr<T const, EmptyDeleter<T const>> const ptr(static_cast<T const *>(dptr));
|
||||
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
};
|
||||
|
||||
map.insert( { std::move(key), std::move(serializers) } );
|
||||
}
|
||||
};
|
||||
|
||||
//! Used to help out argument dependent lookup for finding potential overloads
|
||||
//! of instantiate_polymorphic_binding
|
||||
struct adl_tag {};
|
||||
|
||||
//! Tag for init_binding, bind_to_archives and instantiate_polymorphic_binding. Due to the use of anonymous
|
||||
//! namespace it becomes a different type in each translation unit.
|
||||
namespace { struct polymorphic_binding_tag {}; }
|
||||
|
||||
//! Causes the static object bindings between an archive type and a serializable type T
|
||||
template <class Archive, class T>
|
||||
struct create_bindings
|
||||
{
|
||||
static const InputBindingCreator<Archive, T> &
|
||||
load(std::true_type)
|
||||
{
|
||||
return cereal::detail::StaticObject<InputBindingCreator<Archive, T>>::getInstance();
|
||||
}
|
||||
|
||||
static const OutputBindingCreator<Archive, T> &
|
||||
save(std::true_type)
|
||||
{
|
||||
return cereal::detail::StaticObject<OutputBindingCreator<Archive, T>>::getInstance();
|
||||
}
|
||||
|
||||
inline static void load(std::false_type) {}
|
||||
inline static void save(std::false_type) {}
|
||||
};
|
||||
|
||||
//! When specialized, causes the compiler to instantiate its parameter
|
||||
template <void(*)()>
|
||||
struct instantiate_function {};
|
||||
|
||||
/*! This struct is used as the return type of instantiate_polymorphic_binding
|
||||
for specific Archive types. When the compiler looks for overloads of
|
||||
instantiate_polymorphic_binding, it will be forced to instantiate this
|
||||
struct during overload resolution, even though it will not be part of a valid
|
||||
overload */
|
||||
template <class Archive, class T>
|
||||
struct polymorphic_serialization_support
|
||||
{
|
||||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
|
||||
//! Creates the appropriate bindings depending on whether the archive supports
|
||||
//! saving or loading
|
||||
virtual CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
|
||||
#else // NOT _MSC_VER
|
||||
//! Creates the appropriate bindings depending on whether the archive supports
|
||||
//! saving or loading
|
||||
static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
|
||||
//! This typedef causes the compiler to instantiate this static function
|
||||
typedef instantiate_function<instantiate> unused;
|
||||
#endif // _MSC_VER
|
||||
};
|
||||
|
||||
// instantiate implementation
|
||||
template <class Archive, class T>
|
||||
CEREAL_DLL_EXPORT void polymorphic_serialization_support<Archive,T>::instantiate()
|
||||
{
|
||||
create_bindings<Archive,T>::save( std::integral_constant<bool,
|
||||
std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
|
||||
traits::is_output_serializable<T, Archive>::value>{} );
|
||||
|
||||
create_bindings<Archive,T>::load( std::integral_constant<bool,
|
||||
std::is_base_of<detail::InputArchiveBase, Archive>::value &&
|
||||
traits::is_input_serializable<T, Archive>::value>{} );
|
||||
}
|
||||
|
||||
//! Begins the binding process of a type to all registered archives
|
||||
/*! Archives need to be registered prior to this struct being instantiated via
|
||||
the CEREAL_REGISTER_ARCHIVE macro. Overload resolution will then force
|
||||
several static objects to be made that allow us to bind together all
|
||||
registered archive types with the parameter type T. */
|
||||
template <class T, class Tag = polymorphic_binding_tag>
|
||||
struct bind_to_archives
|
||||
{
|
||||
//! Binding for non abstract types
|
||||
void bind(std::false_type) const
|
||||
{
|
||||
instantiate_polymorphic_binding((T*) 0, 0, Tag{}, adl_tag{});
|
||||
}
|
||||
|
||||
//! Binding for abstract types
|
||||
void bind(std::true_type) const
|
||||
{ }
|
||||
|
||||
//! Binds the type T to all registered archives
|
||||
/*! If T is abstract, we will not serialize it and thus
|
||||
do not need to make a binding */
|
||||
bind_to_archives const & bind() const
|
||||
{
|
||||
static_assert( std::is_polymorphic<T>::value,
|
||||
"Attempting to register non polymorphic type" );
|
||||
bind( std::is_abstract<T>() );
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
//! Used to hide the static object used to bind T to registered archives
|
||||
template <class T, class Tag = polymorphic_binding_tag>
|
||||
struct init_binding;
|
||||
|
||||
//! Base case overload for instantiation
|
||||
/*! This will end up always being the best overload due to the second
|
||||
parameter always being passed as an int. All other overloads will
|
||||
accept pointers to archive types and have lower precedence than int.
|
||||
|
||||
Since the compiler needs to check all possible overloads, the
|
||||
other overloads created via CEREAL_REGISTER_ARCHIVE, which will have
|
||||
lower precedence due to requring a conversion from int to (Archive*),
|
||||
will cause their return types to be instantiated through the static object
|
||||
mechanisms even though they are never called.
|
||||
|
||||
See the documentation for the other functions to try and understand this */
|
||||
template <class T, typename BindingTag>
|
||||
void instantiate_polymorphic_binding( T*, int, BindingTag, adl_tag ) {}
|
||||
} // namespace detail
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
|
||||
90
libs/cereal/cereal/details/static_object.hpp
Normal file
90
libs/cereal/cereal/details/static_object.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
/*! \file static_object.hpp
|
||||
\brief Internal polymorphism static object support
|
||||
\ingroup Internal */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_DETAILS_STATIC_OBJECT_HPP_
|
||||
#define CEREAL_DETAILS_STATIC_OBJECT_HPP_
|
||||
|
||||
//! Prevent link optimization from removing non-referenced static objects
|
||||
/*! Especially for polymorphic support, we create static objects which
|
||||
may not ever be explicitly referenced. Most linkers will detect this
|
||||
and remove the code causing various unpleasant runtime errors. These
|
||||
macros, adopted from Boost (see force_include.hpp) prevent this
|
||||
(C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
|
||||
Use, modification and distribution is subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt) */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define CEREAL_DLL_EXPORT __declspec(dllexport)
|
||||
# define CEREAL_USED
|
||||
#else // clang or gcc
|
||||
# define CEREAL_DLL_EXPORT
|
||||
# define CEREAL_USED __attribute__ ((__used__))
|
||||
#endif
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
//! A static, pre-execution object
|
||||
/*! This class will create a single copy (singleton) of some
|
||||
type and ensures that merely referencing this type will
|
||||
cause it to be instantiated and initialized pre-execution.
|
||||
For example, this is used heavily in the polymorphic pointer
|
||||
serialization mechanisms to bind various archive types with
|
||||
different polymorphic classes */
|
||||
template <class T>
|
||||
class CEREAL_DLL_EXPORT StaticObject
|
||||
{
|
||||
private:
|
||||
//! Forces instantiation at pre-execution time
|
||||
static void instantiate( T const & ) {}
|
||||
|
||||
static T & create()
|
||||
{
|
||||
static T t;
|
||||
instantiate(instance);
|
||||
return t;
|
||||
}
|
||||
|
||||
StaticObject( StaticObject const & /*other*/ ) {}
|
||||
|
||||
public:
|
||||
static T & getInstance()
|
||||
{
|
||||
return create();
|
||||
}
|
||||
|
||||
private:
|
||||
static T & instance;
|
||||
};
|
||||
|
||||
template <class T> T & StaticObject<T>::instance = StaticObject<T>::create();
|
||||
} // namespace detail
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_DETAILS_STATIC_OBJECT_HPP_
|
||||
1325
libs/cereal/cereal/details/traits.hpp
Normal file
1325
libs/cereal/cereal/details/traits.hpp
Normal file
File diff suppressed because it is too large
Load Diff
84
libs/cereal/cereal/details/util.hpp
Normal file
84
libs/cereal/cereal/details/util.hpp
Normal file
@ -0,0 +1,84 @@
|
||||
/*! \file util.hpp
|
||||
\brief Internal misc utilities
|
||||
\ingroup Internal */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_DETAILS_UTIL_HPP_
|
||||
#define CEREAL_DETAILS_UTIL_HPP_
|
||||
|
||||
#include <typeinfo>
|
||||
#include <string>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
namespace cereal
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
//! Demangles the type encoded in a string
|
||||
/*! @internal */
|
||||
inline std::string demangle( std::string const & name )
|
||||
{ return name; }
|
||||
|
||||
//! Gets the demangled name of a type
|
||||
/*! @internal */
|
||||
template <class T> inline
|
||||
std::string demangledName()
|
||||
{ return typeid( T ).name(); }
|
||||
} // namespace util
|
||||
} // namespace cereal
|
||||
#else // clang or gcc
|
||||
#include <cxxabi.h>
|
||||
#include <cstdlib>
|
||||
namespace cereal
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
//! Demangles the type encoded in a string
|
||||
/*! @internal */
|
||||
inline std::string demangle(std::string mangledName)
|
||||
{
|
||||
int status = 0;
|
||||
char *demangledName = nullptr;
|
||||
std::size_t len;
|
||||
|
||||
demangledName = abi::__cxa_demangle(mangledName.c_str(), 0, &len, &status);
|
||||
|
||||
std::string retName(demangledName);
|
||||
free(demangledName);
|
||||
|
||||
return retName;
|
||||
}
|
||||
|
||||
//! Gets the demangled name of a type
|
||||
/*! @internal */
|
||||
template<class T> inline
|
||||
std::string demangledName()
|
||||
{ return demangle(typeid(T).name()); }
|
||||
}
|
||||
} // namespace cereal
|
||||
#endif // clang or gcc branch of _MSC_VER
|
||||
#endif // CEREAL_DETAILS_UTIL_HPP_
|
||||
125
libs/cereal/cereal/external/base64.hpp
vendored
Normal file
125
libs/cereal/cereal/external/base64.hpp
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright (C) 2004-2008 René Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author 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 source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
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 source code.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
*/
|
||||
|
||||
#ifndef CEREAL_EXTERNAL_BASE64_HPP_
|
||||
#define CEREAL_EXTERNAL_BASE64_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace base64
|
||||
{
|
||||
static const std::string chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
inline std::string encode(unsigned char const* bytes_to_encode, size_t in_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (unsigned char) ((char_array_3[0] & 0xfc) >> 2);
|
||||
char_array_4[1] = (unsigned char) ( ( ( char_array_3[0] & 0x03 ) << 4 ) + ( ( char_array_3[1] & 0xf0 ) >> 4 ) );
|
||||
char_array_4[2] = (unsigned char) ( ( ( char_array_3[1] & 0x0f ) << 2 ) + ( ( char_array_3[2] & 0xc0 ) >> 6 ) );
|
||||
char_array_4[3] = (unsigned char) ( char_array_3[2] & 0x3f );
|
||||
|
||||
for(i = 0; (i <4) ; i++)
|
||||
ret += chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += chars[char_array_4[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
inline std::string decode(std::string const& encoded_string) {
|
||||
size_t in_len = encoded_string.size();
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++)
|
||||
char_array_4[i] = (unsigned char) chars.find( char_array_4[i] );
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j <4; j++)
|
||||
char_array_4[j] = 0;
|
||||
|
||||
for (j = 0; j <4; j++)
|
||||
char_array_4[j] = (unsigned char) chars.find( char_array_4[j] );
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
} // base64
|
||||
#endif // CEREAL_EXTERNAL_BASE64_HPP_
|
||||
821
libs/cereal/cereal/external/rapidjson/document.h
vendored
Normal file
821
libs/cereal/cereal/external/rapidjson/document.h
vendored
Normal file
@ -0,0 +1,821 @@
|
||||
#ifndef RAPIDJSON_DOCUMENT_H_
|
||||
#define RAPIDJSON_DOCUMENT_H_
|
||||
|
||||
#include "reader.h"
|
||||
#include "internal/strfunc.h"
|
||||
#include <new> // placement new
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericValue
|
||||
|
||||
//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
|
||||
/*!
|
||||
A JSON value can be one of 7 types. This class is a variant type supporting
|
||||
these types.
|
||||
|
||||
Use the Value if UTF8 and default allocator
|
||||
|
||||
\tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
|
||||
\tparam Allocator Allocator type for allocating memory of object, array and string.
|
||||
*/
|
||||
#pragma pack (push, 4)
|
||||
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
|
||||
class GenericValue {
|
||||
public:
|
||||
//! Name-value pair in an object.
|
||||
struct Member {
|
||||
GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
|
||||
GenericValue<Encoding, Allocator> value; //!< value of member.
|
||||
};
|
||||
|
||||
typedef Encoding EncodingType; //!< Encoding type from template parameter.
|
||||
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
|
||||
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
|
||||
typedef Member* MemberIterator; //!< Member iterator for iterating in object.
|
||||
typedef const Member* ConstMemberIterator; //!< Constant member iterator for iterating in object.
|
||||
typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
|
||||
typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
|
||||
|
||||
//!@name Constructors and destructor.
|
||||
//@{
|
||||
|
||||
//! Default constructor creates a null value.
|
||||
GenericValue() : flags_(kNull_Flag) {}
|
||||
|
||||
//! Copy constructor is not permitted.
|
||||
private:
|
||||
GenericValue(const GenericValue& rhs);
|
||||
|
||||
public:
|
||||
|
||||
//! Constructor with JSON value type.
|
||||
/*! This creates a Value of specified type with default content.
|
||||
\param type Type of the value.
|
||||
\note Default content for number is zero.
|
||||
*/
|
||||
GenericValue(Type type) {
|
||||
static const unsigned defaultFlags[7] = {
|
||||
kNull_Flag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag,
|
||||
kNumberFlag | kIntFlag | kUintFlag | kInt64Flag | kUint64Flag | kDoubleFlag
|
||||
};
|
||||
RAPIDJSON_ASSERT(type <= kNumberType);
|
||||
flags_ = defaultFlags[type];
|
||||
memset(&data_, 0, sizeof(data_));
|
||||
}
|
||||
|
||||
//! Constructor for boolean value.
|
||||
GenericValue(bool b) : flags_(b ? kTrueFlag : kFalseFlag) {}
|
||||
|
||||
//! Constructor for int value.
|
||||
GenericValue(int i) : flags_(kNumberIntFlag) {
|
||||
data_.n.i64 = i;
|
||||
if (i >= 0)
|
||||
flags_ |= kUintFlag | kUint64Flag;
|
||||
}
|
||||
|
||||
//! Constructor for unsigned value.
|
||||
GenericValue(unsigned u) : flags_(kNumberUintFlag) {
|
||||
data_.n.u64 = u;
|
||||
if (!(u & 0x80000000))
|
||||
flags_ |= kIntFlag | kInt64Flag;
|
||||
}
|
||||
|
||||
//! Constructor for int64_t value.
|
||||
GenericValue(int64_t i64) : flags_(kNumberInt64Flag) {
|
||||
data_.n.i64 = i64;
|
||||
if (i64 >= 0) {
|
||||
flags_ |= kNumberUint64Flag;
|
||||
if (!(i64 & 0xFFFFFFFF00000000LL))
|
||||
flags_ |= kUintFlag;
|
||||
if (!(i64 & 0xFFFFFFFF80000000LL))
|
||||
flags_ |= kIntFlag;
|
||||
}
|
||||
else if (i64 >= -2147483648LL)
|
||||
flags_ |= kIntFlag;
|
||||
}
|
||||
|
||||
//! Constructor for uint64_t value.
|
||||
GenericValue(uint64_t u64) : flags_(kNumberUint64Flag) {
|
||||
data_.n.u64 = u64;
|
||||
if (!(u64 & 0x8000000000000000ULL))
|
||||
flags_ |= kInt64Flag;
|
||||
if (!(u64 & 0xFFFFFFFF00000000ULL))
|
||||
flags_ |= kUintFlag;
|
||||
if (!(u64 & 0xFFFFFFFF80000000ULL))
|
||||
flags_ |= kIntFlag;
|
||||
}
|
||||
|
||||
//! Constructor for double value.
|
||||
GenericValue(double d) : flags_(kNumberDoubleFlag) { data_.n.d = d; }
|
||||
|
||||
//! Constructor for constant string (i.e. do not make a copy of string)
|
||||
GenericValue(const Ch* s, SizeType length) {
|
||||
RAPIDJSON_ASSERT(s != NULL);
|
||||
flags_ = kConstStringFlag;
|
||||
data_.s.str = s;
|
||||
data_.s.length = length;
|
||||
}
|
||||
|
||||
//! Constructor for constant string (i.e. do not make a copy of string)
|
||||
GenericValue(const Ch* s) { SetStringRaw(s, internal::StrLen(s)); }
|
||||
|
||||
//! Constructor for copy-string (i.e. do make a copy of string)
|
||||
GenericValue(const Ch* s, SizeType length, Allocator& allocator) { SetStringRaw(s, length, allocator); }
|
||||
|
||||
//! Constructor for copy-string (i.e. do make a copy of string)
|
||||
GenericValue(const Ch*s, Allocator& allocator) { SetStringRaw(s, internal::StrLen(s), allocator); }
|
||||
|
||||
//! Destructor.
|
||||
/*! Need to destruct elements of array, members of object, or copy-string.
|
||||
*/
|
||||
~GenericValue() {
|
||||
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
|
||||
switch(flags_) {
|
||||
case kArrayFlag:
|
||||
for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
|
||||
v->~GenericValue();
|
||||
Allocator::Free(data_.a.elements);
|
||||
break;
|
||||
|
||||
case kObjectFlag:
|
||||
for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {
|
||||
m->name.~GenericValue();
|
||||
m->value.~GenericValue();
|
||||
}
|
||||
Allocator::Free(data_.o.members);
|
||||
break;
|
||||
|
||||
case kCopyStringFlag:
|
||||
Allocator::Free(const_cast<Ch*>(data_.s.str));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//!@name Assignment operators
|
||||
//@{
|
||||
|
||||
//! Assignment with move semantics.
|
||||
/*! \param rhs Source of the assignment. It will become a null value after assignment.
|
||||
*/
|
||||
GenericValue& operator=(GenericValue& rhs) {
|
||||
RAPIDJSON_ASSERT(this != &rhs);
|
||||
this->~GenericValue();
|
||||
memcpy(this, &rhs, sizeof(GenericValue));
|
||||
rhs.flags_ = kNull_Flag;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Assignment with primitive types.
|
||||
/*! \tparam T Either Type, int, unsigned, int64_t, uint64_t, const Ch*
|
||||
\param value The value to be assigned.
|
||||
*/
|
||||
template <typename T>
|
||||
GenericValue& operator=(T value) {
|
||||
this->~GenericValue();
|
||||
new (this) GenericValue(value);
|
||||
return *this;
|
||||
}
|
||||
//@}
|
||||
|
||||
//!@name Type
|
||||
//@{
|
||||
|
||||
Type GetType() const { return static_cast<Type>(flags_ & kTypeMask); }
|
||||
bool IsNull_() const { return flags_ == kNull_Flag; }
|
||||
bool IsFalse() const { return flags_ == kFalseFlag; }
|
||||
bool IsTrue() const { return flags_ == kTrueFlag; }
|
||||
bool IsBool_() const { return (flags_ & kBool_Flag) != 0; }
|
||||
bool IsObject() const { return flags_ == kObjectFlag; }
|
||||
bool IsArray() const { return flags_ == kArrayFlag; }
|
||||
bool IsNumber() const { return (flags_ & kNumberFlag) != 0; }
|
||||
bool IsInt() const { return (flags_ & kIntFlag) != 0; }
|
||||
bool IsUint() const { return (flags_ & kUintFlag) != 0; }
|
||||
bool IsInt64() const { return (flags_ & kInt64Flag) != 0; }
|
||||
bool IsUint64() const { return (flags_ & kUint64Flag) != 0; }
|
||||
bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }
|
||||
bool IsString() const { return (flags_ & kStringFlag) != 0; }
|
||||
|
||||
//@}
|
||||
|
||||
//!@name Null_
|
||||
//@{
|
||||
|
||||
GenericValue& SetNull_() { this->~GenericValue(); new (this) GenericValue(); return *this; }
|
||||
|
||||
//@}
|
||||
|
||||
//!@name Bool_
|
||||
//@{
|
||||
|
||||
bool GetBool_() const { RAPIDJSON_ASSERT(IsBool_()); return flags_ == kTrueFlag; }
|
||||
GenericValue& SetBool_(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
|
||||
|
||||
//@}
|
||||
|
||||
//!@name Object
|
||||
//@{
|
||||
|
||||
//! Set this value as an empty object.
|
||||
GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
|
||||
|
||||
//! Get the value associated with the object's name.
|
||||
GenericValue& operator[](const Ch* name) {
|
||||
if (Member* member = FindMember(name))
|
||||
return member->value;
|
||||
else {
|
||||
static GenericValue Null_Value;
|
||||
return Null_Value;
|
||||
}
|
||||
}
|
||||
const GenericValue& operator[](const Ch* name) const { return const_cast<GenericValue&>(*this)[name]; }
|
||||
|
||||
//! Member iterators.
|
||||
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
|
||||
ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
|
||||
MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
|
||||
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
|
||||
|
||||
//! Check whether a member exists in the object.
|
||||
bool HasMember(const Ch* name) const { return FindMember(name) != 0; }
|
||||
|
||||
//! Add a member (name-value pair) to the object.
|
||||
/*! \param name A string value as name of member.
|
||||
\param value Value of any type.
|
||||
\param allocator Allocator for reallocating memory.
|
||||
\return The value itself for fluent API.
|
||||
\note The ownership of name and value will be transfered to this object if success.
|
||||
*/
|
||||
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
RAPIDJSON_ASSERT(name.IsString());
|
||||
Object& o = data_.o;
|
||||
if (o.size >= o.capacity) {
|
||||
if (o.capacity == 0) {
|
||||
o.capacity = kDefaultObjectCapacity;
|
||||
o.members = (Member*)allocator.Malloc(o.capacity * sizeof(Member));
|
||||
}
|
||||
else {
|
||||
SizeType oldCapacity = o.capacity;
|
||||
o.capacity *= 2;
|
||||
o.members = (Member*)allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member));
|
||||
}
|
||||
}
|
||||
o.members[o.size].name.RawAssign(name);
|
||||
o.members[o.size].value.RawAssign(value);
|
||||
o.size++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
GenericValue& AddMember(const Ch* name, Allocator& nameAllocator, GenericValue& value, Allocator& allocator) {
|
||||
GenericValue n(name, internal::StrLen(name), nameAllocator);
|
||||
return AddMember(n, value, allocator);
|
||||
}
|
||||
|
||||
GenericValue& AddMember(const Ch* name, GenericValue& value, Allocator& allocator) {
|
||||
GenericValue n(name, internal::StrLen(name));
|
||||
return AddMember(n, value, allocator);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
GenericValue& AddMember(const Ch* name, T value, Allocator& allocator) {
|
||||
GenericValue n(name, internal::StrLen(name));
|
||||
GenericValue v(value);
|
||||
return AddMember(n, v, allocator);
|
||||
}
|
||||
|
||||
//! Remove a member in object by its name.
|
||||
/*! \param name Name of member to be removed.
|
||||
\return Whether the member existed.
|
||||
\note Removing member is implemented by moving the last member. So the ordering of members is changed.
|
||||
*/
|
||||
bool RemoveMember(const Ch* name) {
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
if (Member* m = FindMember(name)) {
|
||||
RAPIDJSON_ASSERT(data_.o.size > 0);
|
||||
RAPIDJSON_ASSERT(data_.o.members != 0);
|
||||
|
||||
Member* last = data_.o.members + (data_.o.size - 1);
|
||||
if (data_.o.size > 1 && m != last) {
|
||||
// Move the last one to this place
|
||||
m->name = last->name;
|
||||
m->value = last->value;
|
||||
}
|
||||
else {
|
||||
// Only one left, just destroy
|
||||
m->name.~GenericValue();
|
||||
m->value.~GenericValue();
|
||||
}
|
||||
--data_.o.size;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//!@name Array
|
||||
//@{
|
||||
|
||||
//! Set this value as an empty array.
|
||||
GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
|
||||
|
||||
//! Get the number of elements in array.
|
||||
SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
|
||||
|
||||
//! Get the capacity of array.
|
||||
SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
|
||||
|
||||
//! Check whether the array is empty.
|
||||
bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
|
||||
|
||||
//! Remove all elements in the array.
|
||||
/*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
|
||||
*/
|
||||
void Clear() {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
for (SizeType i = 0; i < data_.a.size; ++i)
|
||||
data_.a.elements[i].~GenericValue();
|
||||
data_.a.size = 0;
|
||||
}
|
||||
|
||||
//! Get an element from array by index.
|
||||
/*! \param index Zero-based index of element.
|
||||
\note
|
||||
\code
|
||||
Value a(kArrayType);
|
||||
a.PushBack(123);
|
||||
int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
|
||||
int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work.
|
||||
int z = a[0u].GetInt(); // This works too.
|
||||
\endcode
|
||||
*/
|
||||
GenericValue& operator[](SizeType index) {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
RAPIDJSON_ASSERT(index < data_.a.size);
|
||||
return data_.a.elements[index];
|
||||
}
|
||||
const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
|
||||
|
||||
//! Element iterator
|
||||
ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }
|
||||
ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }
|
||||
ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
|
||||
ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
|
||||
|
||||
//! Request the array to have enough capacity to store elements.
|
||||
/*! \param newCapacity The capacity that the array at least need to have.
|
||||
\param allocator The allocator for allocating memory. It must be the same one use previously.
|
||||
\return The value itself for fluent API.
|
||||
*/
|
||||
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
if (newCapacity > data_.a.capacity) {
|
||||
data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue));
|
||||
data_.a.capacity = newCapacity;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Append a value at the end of the array.
|
||||
/*! \param value The value to be appended.
|
||||
\param allocator The allocator for allocating memory. It must be the same one use previously.
|
||||
\return The value itself for fluent API.
|
||||
\note The ownership of the value will be transfered to this object if success.
|
||||
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
|
||||
*/
|
||||
GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
if (data_.a.size >= data_.a.capacity)
|
||||
Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : data_.a.capacity * 2, allocator);
|
||||
data_.a.elements[data_.a.size++].RawAssign(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
GenericValue& PushBack(T value, Allocator& allocator) {
|
||||
GenericValue v(value);
|
||||
return PushBack(v, allocator);
|
||||
}
|
||||
|
||||
//! Remove the last element in the array.
|
||||
GenericValue& PopBack() {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
RAPIDJSON_ASSERT(!Empty());
|
||||
data_.a.elements[--data_.a.size].~GenericValue();
|
||||
return *this;
|
||||
}
|
||||
//@}
|
||||
|
||||
//!@name Number
|
||||
//@{
|
||||
|
||||
int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; }
|
||||
unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; }
|
||||
int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }
|
||||
uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }
|
||||
|
||||
double GetDouble() const {
|
||||
RAPIDJSON_ASSERT(IsNumber());
|
||||
if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
|
||||
if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double
|
||||
if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
|
||||
if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision)
|
||||
RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision)
|
||||
}
|
||||
|
||||
GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
|
||||
GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; }
|
||||
GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
|
||||
GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
|
||||
GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
|
||||
|
||||
//@}
|
||||
|
||||
//!@name String
|
||||
//@{
|
||||
|
||||
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
|
||||
|
||||
//! Get the length of string.
|
||||
/*! Since rapidjson permits "\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
|
||||
*/
|
||||
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return data_.s.length; }
|
||||
|
||||
//! Set this value as a string without copying source string.
|
||||
/*! This version has better performance with supplied length, and also support string containing null character.
|
||||
\param s source string pointer.
|
||||
\param length The length of source string, excluding the trailing null terminator.
|
||||
\return The value itself for fluent API.
|
||||
*/
|
||||
GenericValue& SetString(const Ch* s, SizeType length) { this->~GenericValue(); SetStringRaw(s, length); return *this; }
|
||||
|
||||
//! Set this value as a string without copying source string.
|
||||
/*! \param s source string pointer.
|
||||
\return The value itself for fluent API.
|
||||
*/
|
||||
GenericValue& SetString(const Ch* s) { return SetString(s, internal::StrLen(s)); }
|
||||
|
||||
//! Set this value as a string by copying from source string.
|
||||
/*! This version has better performance with supplied length, and also support string containing null character.
|
||||
\param s source string.
|
||||
\param length The length of source string, excluding the trailing null terminator.
|
||||
\param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
|
||||
\return The value itself for fluent API.
|
||||
*/
|
||||
GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, length, allocator); return *this; }
|
||||
|
||||
//! Set this value as a string by copying from source string.
|
||||
/*! \param s source string.
|
||||
\param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
|
||||
\return The value itself for fluent API.
|
||||
*/
|
||||
GenericValue& SetString(const Ch* s, Allocator& allocator) { SetString(s, internal::StrLen(s), allocator); return *this; }
|
||||
|
||||
//@}
|
||||
|
||||
//! Generate events of this value to a Handler.
|
||||
/*! This function adopts the GoF visitor pattern.
|
||||
Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
|
||||
It can also be used to deep clone this value via GenericDocument, which is also a Handler.
|
||||
\tparam Handler type of handler.
|
||||
\param handler An object implementing concept Handler.
|
||||
*/
|
||||
template <typename Handler>
|
||||
const GenericValue& Accept(Handler& handler) const {
|
||||
switch(GetType()) {
|
||||
case kNull_Type: handler.Null_(); break;
|
||||
case kFalseType: handler.Bool_(false); break;
|
||||
case kTrueType: handler.Bool_(true); break;
|
||||
|
||||
case kObjectType:
|
||||
handler.StartObject();
|
||||
for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {
|
||||
handler.String(m->name.data_.s.str, m->name.data_.s.length, false);
|
||||
m->value.Accept(handler);
|
||||
}
|
||||
handler.EndObject(data_.o.size);
|
||||
break;
|
||||
|
||||
case kArrayType:
|
||||
handler.StartArray();
|
||||
for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
|
||||
v->Accept(handler);
|
||||
handler.EndArray(data_.a.size);
|
||||
break;
|
||||
|
||||
case kStringType:
|
||||
handler.String(data_.s.str, data_.s.length, false);
|
||||
break;
|
||||
|
||||
case kNumberType:
|
||||
if (IsInt()) handler.Int(data_.n.i.i);
|
||||
else if (IsUint()) handler.Uint(data_.n.u.u);
|
||||
else if (IsInt64()) handler.Int64(data_.n.i64);
|
||||
else if (IsUint64()) handler.Uint64(data_.n.u64);
|
||||
else handler.Double(data_.n.d);
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename, typename>
|
||||
friend class GenericDocument;
|
||||
|
||||
enum {
|
||||
kBool_Flag = 0x100,
|
||||
kNumberFlag = 0x200,
|
||||
kIntFlag = 0x400,
|
||||
kUintFlag = 0x800,
|
||||
kInt64Flag = 0x1000,
|
||||
kUint64Flag = 0x2000,
|
||||
kDoubleFlag = 0x4000,
|
||||
kStringFlag = 0x100000,
|
||||
kCopyFlag = 0x200000,
|
||||
|
||||
// Initial flags of different types.
|
||||
kNull_Flag = kNull_Type,
|
||||
kTrueFlag = kTrueType | kBool_Flag,
|
||||
kFalseFlag = kFalseType | kBool_Flag,
|
||||
kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
|
||||
kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
|
||||
kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
|
||||
kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
|
||||
kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
|
||||
kConstStringFlag = kStringType | kStringFlag,
|
||||
kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
|
||||
kObjectFlag = kObjectType,
|
||||
kArrayFlag = kArrayType,
|
||||
|
||||
kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler
|
||||
};
|
||||
|
||||
static const SizeType kDefaultArrayCapacity = 16;
|
||||
static const SizeType kDefaultObjectCapacity = 16;
|
||||
|
||||
struct String {
|
||||
const Ch* str;
|
||||
SizeType length;
|
||||
unsigned hashcode; //!< reserved
|
||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||
|
||||
// By using proper binary layout, retrieval of different integer types do not need conversions.
|
||||
union Number {
|
||||
#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
|
||||
struct I {
|
||||
int i;
|
||||
char padding[4];
|
||||
}i;
|
||||
struct U {
|
||||
unsigned u;
|
||||
char padding2[4];
|
||||
}u;
|
||||
#else
|
||||
struct I {
|
||||
char padding[4];
|
||||
int i;
|
||||
}i;
|
||||
struct U {
|
||||
char padding2[4];
|
||||
unsigned u;
|
||||
}u;
|
||||
#endif
|
||||
int64_t i64;
|
||||
uint64_t u64;
|
||||
double d;
|
||||
}; // 8 bytes
|
||||
|
||||
struct Object {
|
||||
Member* members;
|
||||
SizeType size;
|
||||
SizeType capacity;
|
||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||
|
||||
struct Array {
|
||||
GenericValue<Encoding, Allocator>* elements;
|
||||
SizeType size;
|
||||
SizeType capacity;
|
||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||
|
||||
union Data {
|
||||
String s;
|
||||
Number n;
|
||||
Object o;
|
||||
Array a;
|
||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||
|
||||
//! Find member by name.
|
||||
Member* FindMember(const Ch* name) {
|
||||
RAPIDJSON_ASSERT(name);
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
|
||||
SizeType length = internal::StrLen(name);
|
||||
|
||||
Object& o = data_.o;
|
||||
for (Member* member = o.members; member != data_.o.members + data_.o.size; ++member)
|
||||
if (length == member->name.data_.s.length && memcmp(member->name.data_.s.str, name, length * sizeof(Ch)) == 0)
|
||||
return member;
|
||||
|
||||
return 0;
|
||||
}
|
||||
const Member* FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
||||
|
||||
// Initialize this value as array with initial data, without calling destructor.
|
||||
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& alloctaor) {
|
||||
flags_ = kArrayFlag;
|
||||
data_.a.elements = (GenericValue*)alloctaor.Malloc(count * sizeof(GenericValue));
|
||||
memcpy(data_.a.elements, values, count * sizeof(GenericValue));
|
||||
data_.a.size = data_.a.capacity = count;
|
||||
}
|
||||
|
||||
//! Initialize this value as object with initial data, without calling destructor.
|
||||
void SetObjectRaw(Member* members, SizeType count, Allocator& alloctaor) {
|
||||
flags_ = kObjectFlag;
|
||||
data_.o.members = (Member*)alloctaor.Malloc(count * sizeof(Member));
|
||||
memcpy(data_.o.members, members, count * sizeof(Member));
|
||||
data_.o.size = data_.o.capacity = count;
|
||||
}
|
||||
|
||||
//! Initialize this value as constant string, without calling destructor.
|
||||
void SetStringRaw(const Ch* s, SizeType length) {
|
||||
RAPIDJSON_ASSERT(s != NULL);
|
||||
flags_ = kConstStringFlag;
|
||||
data_.s.str = s;
|
||||
data_.s.length = length;
|
||||
}
|
||||
|
||||
//! Initialize this value as copy string with initial data, without calling destructor.
|
||||
void SetStringRaw(const Ch* s, SizeType length, Allocator& allocator) {
|
||||
RAPIDJSON_ASSERT(s != NULL);
|
||||
flags_ = kCopyStringFlag;
|
||||
data_.s.str = (Ch *)allocator.Malloc((length + 1) * sizeof(Ch));
|
||||
data_.s.length = length;
|
||||
memcpy(const_cast<Ch*>(data_.s.str), s, length * sizeof(Ch));
|
||||
const_cast<Ch*>(data_.s.str)[length] = '\0';
|
||||
}
|
||||
|
||||
//! Assignment without calling destructor
|
||||
void RawAssign(GenericValue& rhs) {
|
||||
memcpy(this, &rhs, sizeof(GenericValue));
|
||||
rhs.flags_ = kNull_Flag;
|
||||
}
|
||||
|
||||
Data data_;
|
||||
unsigned flags_;
|
||||
};
|
||||
#pragma pack (pop)
|
||||
|
||||
//! Value with UTF8 encoding.
|
||||
typedef GenericValue<UTF8<> > Value;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericDocument
|
||||
|
||||
//! A document for parsing JSON text as DOM.
|
||||
/*!
|
||||
\implements Handler
|
||||
\tparam Encoding encoding for both parsing and string storage.
|
||||
\tparam Alloactor allocator for allocating memory for the DOM, and the stack during parsing.
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
|
||||
class GenericDocument : public GenericValue<Encoding, Allocator> {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
|
||||
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
|
||||
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
|
||||
|
||||
//! Constructor
|
||||
/*! \param allocator Optional allocator for allocating stack memory.
|
||||
\param stackCapacity Initial capacity of stack in bytes.
|
||||
*/
|
||||
GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}
|
||||
|
||||
//! Parse JSON text from an input stream.
|
||||
/*! \tparam parseFlags Combination of ParseFlag.
|
||||
\param stream Input stream to be parsed.
|
||||
\return The document itself for fluent API.
|
||||
*/
|
||||
template <unsigned parseFlags, typename Stream>
|
||||
GenericDocument& ParseStream(Stream& stream) {
|
||||
ValueType::SetNull_(); // Remove existing root if exist
|
||||
GenericReader<Encoding, Allocator> reader;
|
||||
if (reader.template Parse<parseFlags>(stream, *this)) {
|
||||
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
|
||||
this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this-> to prevent issue 13.
|
||||
parseError_ = 0;
|
||||
errorOffset_ = 0;
|
||||
}
|
||||
else {
|
||||
parseError_ = reader.GetParseError();
|
||||
errorOffset_ = reader.GetErrorOffset();
|
||||
ClearStack();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Parse JSON text from a mutable string.
|
||||
/*! \tparam parseFlags Combination of ParseFlag.
|
||||
\param str Mutable zero-terminated string to be parsed.
|
||||
\return The document itself for fluent API.
|
||||
*/
|
||||
template <unsigned parseFlags>
|
||||
GenericDocument& ParseInsitu(Ch* str) {
|
||||
GenericInsituStringStream<Encoding> s(str);
|
||||
return ParseStream<parseFlags | kParseInsituFlag>(s);
|
||||
}
|
||||
|
||||
//! Parse JSON text from a read-only string.
|
||||
/*! \tparam parseFlags Combination of ParseFlag (must not contain kParseInsituFlag).
|
||||
\param str Read-only zero-terminated string to be parsed.
|
||||
*/
|
||||
template <unsigned parseFlags>
|
||||
GenericDocument& Parse(const Ch* str) {
|
||||
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
|
||||
GenericStringStream<Encoding> s(str);
|
||||
return ParseStream<parseFlags>(s);
|
||||
}
|
||||
|
||||
//! Whether a parse error was occured in the last parsing.
|
||||
bool HasParseError() const { return parseError_ != 0; }
|
||||
|
||||
//! Get the message of parsing error.
|
||||
const char* GetParseError() const { return parseError_; }
|
||||
|
||||
//! Get the offset in character of the parsing error.
|
||||
size_t GetErrorOffset() const { return errorOffset_; }
|
||||
|
||||
//! Get the allocator of this document.
|
||||
Allocator& GetAllocator() { return stack_.GetAllocator(); }
|
||||
|
||||
//! Get the capacity of stack in bytes.
|
||||
size_t GetStackCapacity() const { return stack_.GetCapacity(); }
|
||||
|
||||
private:
|
||||
// Prohibit assignment
|
||||
GenericDocument& operator=(const GenericDocument&);
|
||||
|
||||
friend class GenericReader<Encoding, Allocator>; // for Reader to call the following private handler functions
|
||||
|
||||
// Implementation of Handler
|
||||
void Null_() { new (stack_.template Push<ValueType>()) ValueType(); }
|
||||
void Bool_(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); }
|
||||
void Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); }
|
||||
void Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); }
|
||||
void Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }
|
||||
void Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }
|
||||
void Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); }
|
||||
|
||||
void String(const Ch* str, SizeType length, bool copy) {
|
||||
if (copy)
|
||||
new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
|
||||
else
|
||||
new (stack_.template Push<ValueType>()) ValueType(str, length);
|
||||
}
|
||||
|
||||
void StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); }
|
||||
|
||||
void EndObject(SizeType memberCount) {
|
||||
typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
|
||||
stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
|
||||
}
|
||||
|
||||
void StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); }
|
||||
|
||||
void EndArray(SizeType elementCount) {
|
||||
ValueType* elements = stack_.template Pop<ValueType>(elementCount);
|
||||
stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
|
||||
}
|
||||
|
||||
void ClearStack() {
|
||||
if (Allocator::kNeedFree)
|
||||
while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
|
||||
(stack_.template Pop<ValueType>(1))->~ValueType();
|
||||
else
|
||||
stack_.Clear();
|
||||
}
|
||||
|
||||
static const size_t kDefaultStackCapacity = 1024;
|
||||
internal::Stack<Allocator> stack_;
|
||||
const char* parseError_;
|
||||
size_t errorOffset_;
|
||||
};
|
||||
|
||||
typedef GenericDocument<UTF8<> > Document;
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_DOCUMENT_H_
|
||||
47
libs/cereal/cereal/external/rapidjson/filestream.h
vendored
Normal file
47
libs/cereal/cereal/external/rapidjson/filestream.h
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef RAPIDJSON_FILESTREAM_H_
|
||||
#define RAPIDJSON_FILESTREAM_H_
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Wrapper of C file stream for input or output.
|
||||
/*!
|
||||
This simple wrapper does not check the validity of the stream.
|
||||
\implements Stream
|
||||
*/
|
||||
class FileStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileStream(FILE* fp) : fp_(fp), count_(0) { Read(); }
|
||||
|
||||
char Peek() const { return current_; }
|
||||
char Take() { char c = current_; Read(); return c; }
|
||||
size_t Tell() const { return count_; }
|
||||
void Put(char c) { fputc(c, fp_); }
|
||||
|
||||
// Not implemented
|
||||
char* PutBegin() { return 0; }
|
||||
size_t PutEnd(char*) { return 0; }
|
||||
|
||||
private:
|
||||
void Read() {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
int c = fgetc(fp_);
|
||||
if (c != EOF) {
|
||||
current_ = (char)c;
|
||||
count_++;
|
||||
}
|
||||
else
|
||||
current_ = '\0';
|
||||
}
|
||||
|
||||
FILE* fp_;
|
||||
char current_;
|
||||
size_t count_;
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
105
libs/cereal/cereal/external/rapidjson/genericstream.h
vendored
Normal file
105
libs/cereal/cereal/external/rapidjson/genericstream.h
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
// Generic*Stream code from https://code.google.com/p/rapidjson/issues/detail?id=20
|
||||
#ifndef RAPIDJSON_GENERICSTREAM_H_
|
||||
#define RAPIDJSON_GENERICSTREAM_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include <iostream>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127) // conditional expression is constant
|
||||
#pragma warning(disable: 4512) // assignment operator could not be generated
|
||||
#pragma warning(disable: 4100) // unreferenced formal parameter
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Wrapper of std::istream for input.
|
||||
class GenericReadStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type (byte).
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param is Input stream.
|
||||
*/
|
||||
GenericReadStream(std::istream & is) : is_(&is) {
|
||||
}
|
||||
|
||||
|
||||
Ch Peek() const {
|
||||
if(is_->eof()) return '\0';
|
||||
return static_cast<char>(is_->peek());
|
||||
}
|
||||
|
||||
Ch Take() {
|
||||
if(is_->eof()) return '\0';
|
||||
return static_cast<char>(is_->get());
|
||||
}
|
||||
|
||||
size_t Tell() const {
|
||||
return (int)is_->tellg();
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
std::istream * is_;
|
||||
};
|
||||
|
||||
|
||||
//! Wrapper of std::ostream for output.
|
||||
class GenericWriteStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
//! Constructor
|
||||
/*!
|
||||
\param os Output stream.
|
||||
*/
|
||||
GenericWriteStream(std::ostream& os) : os_(os) {
|
||||
}
|
||||
|
||||
void Put(char c) {
|
||||
os_.put(c);
|
||||
}
|
||||
|
||||
void PutN(char c, size_t n) {
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
Put(c);
|
||||
}
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
os_.flush();
|
||||
}
|
||||
|
||||
size_t Tell() const {
|
||||
return (int)os_.tellp();
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
char Peek() const { RAPIDJSON_ASSERT(false); }
|
||||
char Take() { RAPIDJSON_ASSERT(false); }
|
||||
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
std::ostream& os_;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline void PutN(GenericWriteStream& stream, char c, size_t n) {
|
||||
stream.PutN(c, n);
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
// On MSVC, restore warnings state
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#endif // RAPIDJSON_GENERICSTREAM_H_
|
||||
54
libs/cereal/cereal/external/rapidjson/internal/pow10.h
vendored
Normal file
54
libs/cereal/cereal/external/rapidjson/internal/pow10.h
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef RAPIDJSON_POW10_
|
||||
#define RAPIDJSON_POW10_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
//! Computes integer powers of 10 in double (10.0^n).
|
||||
/*! This function uses lookup table for fast and accurate results.
|
||||
\param n positive/negative exponent. Must <= 308.
|
||||
\return 10.0^n
|
||||
*/
|
||||
inline double Pow10(int n) {
|
||||
static const double e[] = { // 1e-308...1e308: 617 * 8 bytes = 4936 bytes
|
||||
1e-308,1e-307,1e-306,1e-305,1e-304,1e-303,1e-302,1e-301,1e-300,
|
||||
1e-299,1e-298,1e-297,1e-296,1e-295,1e-294,1e-293,1e-292,1e-291,1e-290,1e-289,1e-288,1e-287,1e-286,1e-285,1e-284,1e-283,1e-282,1e-281,1e-280,
|
||||
1e-279,1e-278,1e-277,1e-276,1e-275,1e-274,1e-273,1e-272,1e-271,1e-270,1e-269,1e-268,1e-267,1e-266,1e-265,1e-264,1e-263,1e-262,1e-261,1e-260,
|
||||
1e-259,1e-258,1e-257,1e-256,1e-255,1e-254,1e-253,1e-252,1e-251,1e-250,1e-249,1e-248,1e-247,1e-246,1e-245,1e-244,1e-243,1e-242,1e-241,1e-240,
|
||||
1e-239,1e-238,1e-237,1e-236,1e-235,1e-234,1e-233,1e-232,1e-231,1e-230,1e-229,1e-228,1e-227,1e-226,1e-225,1e-224,1e-223,1e-222,1e-221,1e-220,
|
||||
1e-219,1e-218,1e-217,1e-216,1e-215,1e-214,1e-213,1e-212,1e-211,1e-210,1e-209,1e-208,1e-207,1e-206,1e-205,1e-204,1e-203,1e-202,1e-201,1e-200,
|
||||
1e-199,1e-198,1e-197,1e-196,1e-195,1e-194,1e-193,1e-192,1e-191,1e-190,1e-189,1e-188,1e-187,1e-186,1e-185,1e-184,1e-183,1e-182,1e-181,1e-180,
|
||||
1e-179,1e-178,1e-177,1e-176,1e-175,1e-174,1e-173,1e-172,1e-171,1e-170,1e-169,1e-168,1e-167,1e-166,1e-165,1e-164,1e-163,1e-162,1e-161,1e-160,
|
||||
1e-159,1e-158,1e-157,1e-156,1e-155,1e-154,1e-153,1e-152,1e-151,1e-150,1e-149,1e-148,1e-147,1e-146,1e-145,1e-144,1e-143,1e-142,1e-141,1e-140,
|
||||
1e-139,1e-138,1e-137,1e-136,1e-135,1e-134,1e-133,1e-132,1e-131,1e-130,1e-129,1e-128,1e-127,1e-126,1e-125,1e-124,1e-123,1e-122,1e-121,1e-120,
|
||||
1e-119,1e-118,1e-117,1e-116,1e-115,1e-114,1e-113,1e-112,1e-111,1e-110,1e-109,1e-108,1e-107,1e-106,1e-105,1e-104,1e-103,1e-102,1e-101,1e-100,
|
||||
1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, 1e-81, 1e-80,
|
||||
1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, 1e-63, 1e-62, 1e-61, 1e-60,
|
||||
1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40,
|
||||
1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20,
|
||||
1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e+0,
|
||||
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
|
||||
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
|
||||
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
|
||||
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
|
||||
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
|
||||
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
|
||||
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
|
||||
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
|
||||
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
|
||||
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
|
||||
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
|
||||
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
|
||||
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
|
||||
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
|
||||
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
|
||||
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
|
||||
};
|
||||
RAPIDJSON_ASSERT(n <= 308);
|
||||
return n < -308 ? 0.0 : e[n + 308];
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_POW10_
|
||||
82
libs/cereal/cereal/external/rapidjson/internal/stack.h
vendored
Normal file
82
libs/cereal/cereal/external/rapidjson/internal/stack.h
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stack
|
||||
|
||||
//! A type-unsafe stack for storing different types of data.
|
||||
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||
*/
|
||||
template <typename Allocator>
|
||||
class Stack {
|
||||
public:
|
||||
Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) {
|
||||
RAPIDJSON_ASSERT(stack_capacity_ > 0);
|
||||
if (!allocator_)
|
||||
own_allocator_ = allocator_ = new Allocator();
|
||||
stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_);
|
||||
stack_end_ = stack_ + stack_capacity_;
|
||||
}
|
||||
|
||||
~Stack() {
|
||||
Allocator::Free(stack_);
|
||||
delete own_allocator_; // Only delete if it is owned by the stack
|
||||
}
|
||||
|
||||
void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; }
|
||||
|
||||
template<typename T>
|
||||
T* Push(size_t count = 1) {
|
||||
// Expand the stack if needed
|
||||
if (stack_top_ + sizeof(T) * count >= stack_end_) {
|
||||
size_t new_capacity = stack_capacity_ * 2;
|
||||
size_t size = GetSize();
|
||||
size_t new_size = GetSize() + sizeof(T) * count;
|
||||
if (new_capacity < new_size)
|
||||
new_capacity = new_size;
|
||||
stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity);
|
||||
stack_capacity_ = new_capacity;
|
||||
stack_top_ = stack_ + size;
|
||||
stack_end_ = stack_ + stack_capacity_;
|
||||
}
|
||||
T* ret = (T*)stack_top_;
|
||||
stack_top_ += sizeof(T) * count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Pop(size_t count) {
|
||||
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||
stack_top_ -= count * sizeof(T);
|
||||
return (T*)stack_top_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Top() {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return (T*)(stack_top_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return (T*)stack_; }
|
||||
|
||||
Allocator& GetAllocator() { return *allocator_; }
|
||||
size_t GetSize() const { return stack_top_ - stack_; }
|
||||
size_t GetCapacity() const { return stack_capacity_; }
|
||||
|
||||
private:
|
||||
Allocator* allocator_;
|
||||
Allocator* own_allocator_;
|
||||
char *stack_;
|
||||
char *stack_top_;
|
||||
char *stack_end_;
|
||||
size_t stack_capacity_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_STACK_H_
|
||||
24
libs/cereal/cereal/external/rapidjson/internal/strfunc.h
vendored
Normal file
24
libs/cereal/cereal/external/rapidjson/internal/strfunc.h
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
//! Custom strlen() which works on different character types.
|
||||
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
||||
\param s Null-terminated input string.
|
||||
\return Number of characters in the string.
|
||||
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
|
||||
*/
|
||||
template <typename Ch>
|
||||
inline SizeType StrLen(const Ch* s) {
|
||||
const Ch* p = s;
|
||||
while (*p != '\0')
|
||||
++p;
|
||||
return SizeType(p - s);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
19
libs/cereal/cereal/external/rapidjson/license.txt
vendored
Normal file
19
libs/cereal/cereal/external/rapidjson/license.txt
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (C) 2011 Milo Yip
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
156
libs/cereal/cereal/external/rapidjson/prettywriter.h
vendored
Normal file
156
libs/cereal/cereal/external/rapidjson/prettywriter.h
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
#ifndef RAPIDJSON_PRETTYWRITER_H_
|
||||
#define RAPIDJSON_PRETTYWRITER_H_
|
||||
|
||||
#include "writer.h"
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Writer with indentation and spacing.
|
||||
/*!
|
||||
\tparam Stream Type of ouptut stream.
|
||||
\tparam Encoding Encoding of both source strings and output.
|
||||
\tparam Allocator Type of allocator for allocating memory of stack.
|
||||
*/
|
||||
template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
|
||||
class PrettyWriter : public Writer<Stream, Encoding, Allocator> {
|
||||
public:
|
||||
typedef Writer<Stream, Encoding, Allocator> Base;
|
||||
typedef typename Base::Ch Ch;
|
||||
|
||||
//! Constructor
|
||||
/*! \param stream Output stream.
|
||||
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of
|
||||
*/
|
||||
PrettyWriter(Stream& stream, int precision = 20, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(stream, precision, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
||||
|
||||
//! Set custom indentation.
|
||||
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r').
|
||||
\param indentCharCount Number of indent characters for each indentation level.
|
||||
\note The default indentation is 4 spaces.
|
||||
*/
|
||||
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
|
||||
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
|
||||
indentChar_ = indentChar;
|
||||
indentCharCount_ = indentCharCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//@name Implementation of Handler.
|
||||
//@{
|
||||
|
||||
PrettyWriter& Null_() { PrettyPrefix(kNull_Type); Base::WriteNull_(); return *this; }
|
||||
PrettyWriter& Bool_(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool_(b); return *this; }
|
||||
PrettyWriter& Int(int i) { PrettyPrefix(kNumberType); Base::WriteInt(i); return *this; }
|
||||
PrettyWriter& Uint(unsigned u) { PrettyPrefix(kNumberType); Base::WriteUint(u); return *this; }
|
||||
PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; }
|
||||
PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; }
|
||||
PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; }
|
||||
|
||||
PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
PrettyPrefix(kStringType);
|
||||
Base::WriteString(str, length);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrettyWriter& StartObject() {
|
||||
PrettyPrefix(kObjectType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
|
||||
Base::WriteStartObject();
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrettyWriter& EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty) {
|
||||
Base::stream_.Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
Base::WriteEndObject();
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrettyWriter& StartArray() {
|
||||
PrettyPrefix(kArrayType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
|
||||
Base::WriteStartArray();
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrettyWriter& EndArray(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty) {
|
||||
Base::stream_.Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
Base::WriteEndArray();
|
||||
return *this;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//! Simpler but slower overload.
|
||||
PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
|
||||
protected:
|
||||
void PrettyPrefix(Type type) {
|
||||
(void)type;
|
||||
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
|
||||
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
|
||||
|
||||
if (level->inArray) {
|
||||
if (level->valueCount > 0) {
|
||||
Base::stream_.Put(','); // add comma if it is not the first element in array
|
||||
Base::stream_.Put('\n');
|
||||
}
|
||||
else
|
||||
Base::stream_.Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
else { // in object
|
||||
if (level->valueCount > 0) {
|
||||
if (level->valueCount % 2 == 0) {
|
||||
Base::stream_.Put(',');
|
||||
Base::stream_.Put('\n');
|
||||
}
|
||||
else {
|
||||
Base::stream_.Put(':');
|
||||
Base::stream_.Put(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
Base::stream_.Put('\n');
|
||||
|
||||
if (level->valueCount % 2 == 0)
|
||||
WriteIndent();
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else
|
||||
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
|
||||
}
|
||||
|
||||
void WriteIndent() {
|
||||
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
||||
PutN(Base::stream_, indentChar_, count);
|
||||
}
|
||||
|
||||
Ch indentChar_;
|
||||
unsigned indentCharCount_;
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
525
libs/cereal/cereal/external/rapidjson/rapidjson.h
vendored
Normal file
525
libs/cereal/cereal/external/rapidjson/rapidjson.h
vendored
Normal file
@ -0,0 +1,525 @@
|
||||
#ifndef RAPIDJSON_RAPIDJSON_H_
|
||||
#define RAPIDJSON_RAPIDJSON_H_
|
||||
|
||||
// Copyright (c) 2011-2012 Milo Yip (miloyip@gmail.com)
|
||||
// Version 0.11
|
||||
|
||||
#include <cstdlib> // malloc(), realloc(), free()
|
||||
#include <cstring> // memcpy()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_INT64DEFINE
|
||||
|
||||
// Here defines int64_t and uint64_t types in global namespace.
|
||||
// If user have their own definition, can define RAPIDJSON_NO_INT64DEFINE to disable this.
|
||||
#ifndef RAPIDJSON_NO_INT64DEFINE
|
||||
#ifdef _MSC_VER
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#endif // RAPIDJSON_NO_INT64TYPEDEF
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ENDIAN
|
||||
#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
|
||||
#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
|
||||
|
||||
//! Endianness of the machine.
|
||||
/*! GCC provided macro for detecting endianness of the target machine. But other
|
||||
compilers may not have this. User can define RAPIDJSON_ENDIAN to either
|
||||
RAPIDJSON_LITTLEENDIAN or RAPIDJSON_BIGENDIAN.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ENDIAN
|
||||
#ifdef __BYTE_ORDER__
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
#else
|
||||
#define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
#endif // __BYTE_ORDER__
|
||||
#else
|
||||
#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN // Assumes little endian otherwise.
|
||||
#endif
|
||||
#endif // RAPIDJSON_ENDIAN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
|
||||
|
||||
// Enable SSE2 optimization.
|
||||
//#define RAPIDJSON_SSE2
|
||||
|
||||
// Enable SSE4.2 optimization.
|
||||
//#define RAPIDJSON_SSE42
|
||||
|
||||
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
|
||||
#define RAPIDJSON_SIMD
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
|
||||
#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
namespace rapidjson {
|
||||
//! Use 32-bit array/string indices even for 64-bit platform, instead of using size_t.
|
||||
/*! User may override the SizeType by defining RAPIDJSON_NO_SIZETYPEDEFINE.
|
||||
*/
|
||||
typedef unsigned SizeType;
|
||||
} // namespace rapidjson
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ASSERT
|
||||
|
||||
//! Assertion.
|
||||
/*! By default, rapidjson uses C assert() for assertion.
|
||||
User can override it by defining RAPIDJSON_ASSERT(x) macro.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ASSERT
|
||||
#include <cassert>
|
||||
#define RAPIDJSON_ASSERT(x) assert(x)
|
||||
#endif // RAPIDJSON_ASSERT
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Helpers
|
||||
|
||||
#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
|
||||
#define RAPIDJSON_MULTILINEMACRO_END \
|
||||
} while((void)0, 0)
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allocator
|
||||
|
||||
/*! \class rapidjson::Allocator
|
||||
\brief Concept for allocating, resizing and freeing memory block.
|
||||
|
||||
Note that Malloc() and Realloc() are non-static but Free() is static.
|
||||
|
||||
So if an allocator need to support Free(), it needs to put its pointer in
|
||||
the header of memory block.
|
||||
|
||||
\code
|
||||
concept Allocator {
|
||||
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||
|
||||
// Allocate a memory block.
|
||||
// \param size of the memory block in bytes.
|
||||
// \returns pointer to the memory block.
|
||||
void* Malloc(size_t size);
|
||||
|
||||
// Resize a memory block.
|
||||
// \param originalPtr The pointer to current memory block. Null_ pointer is permitted.
|
||||
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||
// \param newSize the new size in bytes.
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||
|
||||
// Free a memory block.
|
||||
// \param pointer to the memory block. Null_ pointer is permitted.
|
||||
static void Free(void *ptr);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CrtAllocator
|
||||
|
||||
//! C-runtime library allocator.
|
||||
/*! This class is just wrapper for standard C library memory routines.
|
||||
\implements Allocator
|
||||
*/
|
||||
class CrtAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = true;
|
||||
void* Malloc(size_t size) { return malloc(size); }
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); }
|
||||
static void Free(void *ptr) { free(ptr); }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MemoryPoolAllocator
|
||||
|
||||
//! Default memory allocator used by the parser and DOM.
|
||||
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
|
||||
|
||||
It does not free memory blocks. And Realloc() only allocate new memory.
|
||||
|
||||
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
|
||||
|
||||
User may also supply a buffer as the first chunk.
|
||||
|
||||
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
|
||||
|
||||
The user-buffer is not deallocated by this allocator.
|
||||
|
||||
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
|
||||
\implements Allocator
|
||||
*/
|
||||
template <typename BaseAllocator = CrtAllocator>
|
||||
class MemoryPoolAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||
|
||||
//! Constructor with chunkSize.
|
||||
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = new BaseAllocator();
|
||||
AddChunk(chunk_capacity_);
|
||||
}
|
||||
|
||||
//! Constructor with user-supplied buffer.
|
||||
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||
|
||||
The user buffer will not be deallocated when this allocator is destructed.
|
||||
|
||||
\param buffer User supplied buffer.
|
||||
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(char *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||
chunkHead_ = (ChunkHeader*)buffer;
|
||||
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||
chunkHead_->size = 0;
|
||||
chunkHead_->next = 0;
|
||||
}
|
||||
|
||||
//! Destructor.
|
||||
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
*/
|
||||
~MemoryPoolAllocator() {
|
||||
Clear();
|
||||
delete ownBaseAllocator_;
|
||||
}
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while(chunkHead_ != 0 && chunkHead_ != (ChunkHeader *)userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
}
|
||||
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
/*! \return total capacity in bytes.
|
||||
*/
|
||||
size_t Capacity() {
|
||||
size_t capacity = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
capacity += c->capacity;
|
||||
return capacity;
|
||||
}
|
||||
|
||||
//! Computes the memory blocks allocated.
|
||||
/*! \return total used bytes.
|
||||
*/
|
||||
size_t Size() {
|
||||
size_t size = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
size += c->size;
|
||||
return size;
|
||||
}
|
||||
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
size = (size + 3) & ~3; // Force aligning size to 4
|
||||
|
||||
if (chunkHead_->size + size > chunkHead_->capacity)
|
||||
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
||||
|
||||
char *buffer = (char *)(chunkHead_ + 1) + chunkHead_->size;
|
||||
RAPIDJSON_ASSERT(((uintptr_t)buffer & 3) == 0); // returned buffer is aligned to 4
|
||||
chunkHead_->size += size;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//! Resizes a memory block (concept Allocator)
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
if (originalPtr == 0)
|
||||
return Malloc(newSize);
|
||||
|
||||
// Do not shrink if new size is smaller than original
|
||||
if (originalSize >= newSize)
|
||||
return originalPtr;
|
||||
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
|
||||
size_t increment = newSize - originalSize;
|
||||
increment = (increment + 3) & ~3; // Force aligning size to 4
|
||||
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||
chunkHead_->size += increment;
|
||||
RAPIDJSON_ASSERT(((uintptr_t)originalPtr & 3) == 0); // returned buffer is aligned to 4
|
||||
return originalPtr;
|
||||
}
|
||||
}
|
||||
|
||||
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||
void* newBuffer = Malloc(newSize);
|
||||
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
|
||||
return memcpy(newBuffer, originalPtr, originalSize);
|
||||
}
|
||||
|
||||
//! Frees a memory block (concept Allocator)
|
||||
static void Free(void *) {} // Do nothing
|
||||
|
||||
private:
|
||||
//! Creates a new chunk.
|
||||
/*! \param capacity Capacity of the chunk in bytes.
|
||||
*/
|
||||
void AddChunk(size_t capacity) {
|
||||
ChunkHeader* chunk = (ChunkHeader*)baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity);
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
chunkHead_ = chunk;
|
||||
}
|
||||
|
||||
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
|
||||
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
};
|
||||
|
||||
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||
char *userBuffer_; //!< User supplied buffer.
|
||||
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Encoding
|
||||
|
||||
/*! \class rapidjson::Encoding
|
||||
\brief Concept for encoding of Unicode characters.
|
||||
|
||||
\code
|
||||
concept Encoding {
|
||||
typename Ch; //! Type of character.
|
||||
|
||||
//! \brief Encode a Unicode codepoint to a buffer.
|
||||
//! \param buffer pointer to destination buffer to store the result. It should have sufficient size of encoding one character.
|
||||
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
|
||||
//! \returns the pointer to the next character after the encoded data.
|
||||
static Ch* Encode(Ch *buffer, unsigned codepoint);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF8
|
||||
|
||||
//! UTF-8 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-8
|
||||
\tparam CharType Type for storing 8-bit UTF-8 data. Default is char.
|
||||
\implements Encoding
|
||||
*/
|
||||
template<typename CharType = char>
|
||||
struct UTF8 {
|
||||
typedef CharType Ch;
|
||||
|
||||
static Ch* Encode(Ch *buffer, unsigned codepoint) {
|
||||
if (codepoint <= 0x7F)
|
||||
*buffer++ = codepoint & 0xFF;
|
||||
else if (codepoint <= 0x7FF) {
|
||||
*buffer++ = 0xC0 | ((codepoint >> 6) & 0xFF);
|
||||
*buffer++ = 0x80 | ((codepoint & 0x3F));
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) {
|
||||
*buffer++ = 0xE0 | ((codepoint >> 12) & 0xFF);
|
||||
*buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
*buffer++ = 0x80 | (codepoint & 0x3F);
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
*buffer++ = 0xF0 | ((codepoint >> 18) & 0xFF);
|
||||
*buffer++ = 0x80 | ((codepoint >> 12) & 0x3F);
|
||||
*buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
*buffer++ = 0x80 | (codepoint & 0x3F);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF16
|
||||
|
||||
//! UTF-16 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-16
|
||||
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
|
||||
\implements Encoding
|
||||
*/
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16 {
|
||||
typedef CharType Ch;
|
||||
|
||||
static Ch* Encode(Ch* buffer, unsigned codepoint) {
|
||||
if (codepoint <= 0xFFFF) {
|
||||
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||
*buffer++ = static_cast<Ch>(codepoint);
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
unsigned v = codepoint - 0x10000;
|
||||
*buffer++ = static_cast<Ch>((v >> 10) + 0xD800);
|
||||
*buffer++ = (v & 0x3FF) + 0xDC00;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF32
|
||||
|
||||
//! UTF-32 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-32
|
||||
\tparam Ch Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
|
||||
\implements Encoding
|
||||
*/
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32 {
|
||||
typedef CharType Ch;
|
||||
|
||||
static Ch *Encode(Ch* buffer, unsigned codepoint) {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
*buffer++ = codepoint;
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stream
|
||||
|
||||
/*! \class rapidjson::Stream
|
||||
\brief Concept for reading and writing characters.
|
||||
|
||||
For read-only stream, no need to implement PutBegin(), Put() and PutEnd().
|
||||
|
||||
For write-only stream, only need to implement Put().
|
||||
|
||||
\code
|
||||
concept Stream {
|
||||
typename Ch; //!< Character type of the stream.
|
||||
|
||||
//! Read the current character from stream without moving the read cursor.
|
||||
Ch Peek() const;
|
||||
|
||||
//! Read the current character from stream and moving the read cursor to next character.
|
||||
Ch Take();
|
||||
|
||||
//! Get the current read cursor.
|
||||
//! \return Number of characters read from start.
|
||||
size_t Tell();
|
||||
|
||||
//! Begin writing operation at the current read pointer.
|
||||
//! \return The begin writer pointer.
|
||||
Ch* PutBegin();
|
||||
|
||||
//! Write a character.
|
||||
void Put(Ch c);
|
||||
|
||||
//! End the writing operation.
|
||||
//! \param begin The begin write pointer returned by PutBegin().
|
||||
//! \return Number of characters written.
|
||||
size_t PutEnd(Ch* begin);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
//! Put N copies of a character to a stream.
|
||||
template<typename Stream, typename Ch>
|
||||
inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||
for (size_t i = 0; i < n; i++)
|
||||
stream.Put(c);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// StringStream
|
||||
|
||||
//! Read-only string stream.
|
||||
/*! \implements Stream
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringStream(const Ch *src) : src_(src), head_(src) {}
|
||||
|
||||
Ch Peek() const { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() const { return src_ - head_; }
|
||||
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
const Ch* src_; //!< Current read position.
|
||||
const Ch* head_; //!< Original head of the string.
|
||||
};
|
||||
|
||||
typedef GenericStringStream<UTF8<> > StringStream;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// InsituStringStream
|
||||
|
||||
//! A read-write string stream.
|
||||
/*! This string stream is particularly designed for in-situ parsing.
|
||||
\implements Stream
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericInsituStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
|
||||
|
||||
// Read
|
||||
Ch Peek() { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() { return src_ - head_; }
|
||||
|
||||
// Write
|
||||
Ch* PutBegin() { return dst_ = src_; }
|
||||
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
|
||||
size_t PutEnd(Ch* begin) { return dst_ - begin; }
|
||||
|
||||
Ch* src_;
|
||||
Ch* dst_;
|
||||
Ch* head_;
|
||||
};
|
||||
|
||||
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Type
|
||||
|
||||
//! Type of JSON value
|
||||
enum Type {
|
||||
kNull_Type = 0, //!< null
|
||||
kFalseType = 1, //!< false
|
||||
kTrueType = 2, //!< true
|
||||
kObjectType = 3, //!< object
|
||||
kArrayType = 4, //!< array
|
||||
kStringType = 5, //!< string
|
||||
kNumberType = 6, //!< number
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
749
libs/cereal/cereal/external/rapidjson/reader.h
vendored
Normal file
749
libs/cereal/cereal/external/rapidjson/reader.h
vendored
Normal file
@ -0,0 +1,749 @@
|
||||
#ifndef RAPIDJSON_READER_H_
|
||||
#define RAPIDJSON_READER_H_
|
||||
|
||||
// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
|
||||
// Version 0.1
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/pow10.h"
|
||||
#include "internal/stack.h"
|
||||
#include <csetjmp>
|
||||
|
||||
// All part of denormalized parsing
|
||||
#include <limits> // for numeric_limits
|
||||
#include <cmath> // for fpclassify
|
||||
#include <sstream>
|
||||
|
||||
#ifdef RAPIDJSON_SSE42
|
||||
#include <nmmintrin.h>
|
||||
#elif defined(RAPIDJSON_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#pragma warning(disable : 4702) // uncreachable code
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDJSON_PARSE_ERROR
|
||||
#define RAPIDJSON_PARSE_ERROR(msg, offset) \
|
||||
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
||||
parseError_ = msg; \
|
||||
errorOffset_ = offset; \
|
||||
longjmp(jmpbuf_, 1); \
|
||||
RAPIDJSON_MULTILINEMACRO_END
|
||||
#endif
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ParseFlag
|
||||
|
||||
//! Combination of parseFlags
|
||||
enum ParseFlag {
|
||||
kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer.
|
||||
kParseInsituFlag = 1 //!< In-situ(destructive) parsing.
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Handler
|
||||
|
||||
/*! \class rapidjson::Handler
|
||||
\brief Concept for receiving events from GenericReader upon parsing.
|
||||
\code
|
||||
concept Handler {
|
||||
typename Ch;
|
||||
|
||||
void Null_();
|
||||
void Bool_(bool b);
|
||||
void Int(int i);
|
||||
void Uint(unsigned i);
|
||||
void Int64(int64_t i);
|
||||
void Uint64(uint64_t i);
|
||||
void Double(double d);
|
||||
void String(const Ch* str, SizeType length, bool copy);
|
||||
void StartObject();
|
||||
void EndObject(SizeType memberCount);
|
||||
void StartArray();
|
||||
void EndArray(SizeType elementCount);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BaseReaderHandler
|
||||
|
||||
//! Default implementation of Handler.
|
||||
/*! This can be used as base class of any reader handler.
|
||||
\implements Handler
|
||||
*/
|
||||
template<typename Encoding = UTF8<> >
|
||||
struct BaseReaderHandler {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
void Default() {}
|
||||
void Null_() { Default(); }
|
||||
void Bool_(bool) { Default(); }
|
||||
void Int(int) { Default(); }
|
||||
void Uint(unsigned) { Default(); }
|
||||
void Int64(int64_t) { Default(); }
|
||||
void Uint64(uint64_t) { Default(); }
|
||||
void Double(double) { Default(); }
|
||||
void String(const Ch*, SizeType, bool) { Default(); }
|
||||
void StartObject() { Default(); }
|
||||
void EndObject(SizeType) { Default(); }
|
||||
void StartArray() { Default(); }
|
||||
void EndArray(SizeType) { Default(); }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SkipWhitespace
|
||||
|
||||
//! Skip the JSON white spaces in a stream.
|
||||
/*! \param stream A input stream for skipping white spaces.
|
||||
\note This function has SSE2/SSE4.2 specialization.
|
||||
*/
|
||||
template<typename Stream>
|
||||
void SkipWhitespace(Stream& stream) {
|
||||
Stream s = stream; // Use a local copy for optimization
|
||||
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
|
||||
s.Take();
|
||||
stream = s;
|
||||
}
|
||||
|
||||
#ifdef RAPIDJSON_SSE42
|
||||
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
|
||||
inline const char *SkipWhitespace_SIMD(const char* p) {
|
||||
static const char whitespace[16] = " \n\r\t";
|
||||
__m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);
|
||||
|
||||
for (;;) {
|
||||
__m128i s = _mm_loadu_si128((const __m128i *)p);
|
||||
unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
|
||||
if (r == 0) // all 16 characters are whitespace
|
||||
p += 16;
|
||||
else { // some of characters may be non-whitespace
|
||||
#ifdef _MSC_VER // Find the index of first non-whitespace
|
||||
unsigned long offset;
|
||||
if (_BitScanForward(&offset, r))
|
||||
return p + offset;
|
||||
#else
|
||||
if (r != 0)
|
||||
return p + __builtin_ffs(r) - 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(RAPIDJSON_SSE2)
|
||||
|
||||
//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
|
||||
inline const char *SkipWhitespace_SIMD(const char* p) {
|
||||
static const char whitespaces[4][17] = {
|
||||
" ",
|
||||
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
||||
"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
|
||||
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
|
||||
|
||||
__m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
|
||||
__m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
|
||||
__m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
|
||||
__m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);
|
||||
|
||||
for (;;) {
|
||||
__m128i s = _mm_loadu_si128((const __m128i *)p);
|
||||
__m128i x = _mm_cmpeq_epi8(s, w0);
|
||||
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
|
||||
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
|
||||
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
|
||||
unsigned short r = ~_mm_movemask_epi8(x);
|
||||
if (r == 0) // all 16 characters are whitespace
|
||||
p += 16;
|
||||
else { // some of characters may be non-whitespace
|
||||
#ifdef _MSC_VER // Find the index of first non-whitespace
|
||||
unsigned long offset;
|
||||
if (_BitScanForward(&offset, r))
|
||||
return p + offset;
|
||||
#else
|
||||
if (r != 0)
|
||||
return p + __builtin_ffs(r) - 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // RAPIDJSON_SSE2
|
||||
|
||||
#ifdef RAPIDJSON_SIMD
|
||||
//! Template function specialization for InsituStringStream
|
||||
template<> inline void SkipWhitespace(InsituStringStream& stream) {
|
||||
stream.src_ = const_cast<char*>(SkipWhitespace_SIMD(stream.src_));
|
||||
}
|
||||
|
||||
//! Template function specialization for StringStream
|
||||
template<> inline void SkipWhitespace(StringStream& stream) {
|
||||
stream.src_ = SkipWhitespace_SIMD(stream.src_);
|
||||
}
|
||||
#endif // RAPIDJSON_SIMD
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericReader
|
||||
|
||||
//! SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
|
||||
/*! GenericReader parses JSON text from a stream, and send events synchronously to an
|
||||
object implementing Handler concept.
|
||||
|
||||
It needs to allocate a stack for storing a single decoded string during
|
||||
non-destructive parsing.
|
||||
|
||||
For in-situ parsing, the decoded string is directly written to the source
|
||||
text string, no temporary buffer is required.
|
||||
|
||||
A GenericReader object can be reused for parsing multiple JSON text.
|
||||
|
||||
\tparam Encoding Encoding of both the stream and the parse output.
|
||||
\tparam Allocator Allocator type for stack.
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
|
||||
class GenericReader {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
|
||||
\param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
|
||||
*/
|
||||
GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}
|
||||
|
||||
//! Parse JSON text.
|
||||
/*! \tparam parseFlags Combination of ParseFlag.
|
||||
\tparam Stream Type of input stream.
|
||||
\tparam Handler Type of handler which must implement Handler concept.
|
||||
\param stream Input stream to be parsed.
|
||||
\param handler The handler to receive events.
|
||||
\return Whether the parsing is successful.
|
||||
*/
|
||||
template <unsigned parseFlags, typename Stream, typename Handler>
|
||||
bool Parse(Stream& stream, Handler& handler) {
|
||||
parseError_ = 0;
|
||||
errorOffset_ = 0;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
|
||||
#endif
|
||||
if (setjmp(jmpbuf_)) {
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
stack_.Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
SkipWhitespace(stream);
|
||||
|
||||
if (stream.Peek() == '\0')
|
||||
RAPIDJSON_PARSE_ERROR("Text only contains white space(s)", stream.Tell());
|
||||
else {
|
||||
switch (stream.Peek()) {
|
||||
case '{': ParseObject<parseFlags>(stream, handler); break;
|
||||
case '[': ParseArray<parseFlags>(stream, handler); break;
|
||||
default: RAPIDJSON_PARSE_ERROR("Expect either an object or array at root", stream.Tell());
|
||||
}
|
||||
SkipWhitespace(stream);
|
||||
|
||||
if (stream.Peek() != '\0' && stream.Peek() != static_cast<Ch>(std::char_traits<Ch>::eof()))
|
||||
RAPIDJSON_PARSE_ERROR("Nothing should follow the root object or array.", stream.Tell());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasParseError() const { return parseError_ != 0; }
|
||||
const char* GetParseError() const { return parseError_; }
|
||||
size_t GetErrorOffset() const { return errorOffset_; }
|
||||
|
||||
private:
|
||||
// Parse object: { string : value, ... }
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseObject(Stream& stream, Handler& handler) {
|
||||
RAPIDJSON_ASSERT(stream.Peek() == '{');
|
||||
stream.Take(); // Skip '{'
|
||||
handler.StartObject();
|
||||
SkipWhitespace(stream);
|
||||
|
||||
if (stream.Peek() == '}') {
|
||||
stream.Take();
|
||||
handler.EndObject(0); // empty object
|
||||
return;
|
||||
}
|
||||
|
||||
for (SizeType memberCount = 0;;) {
|
||||
if (stream.Peek() != '"') {
|
||||
RAPIDJSON_PARSE_ERROR("Name of an object member must be a string", stream.Tell());
|
||||
break;
|
||||
}
|
||||
|
||||
ParseString<parseFlags>(stream, handler);
|
||||
SkipWhitespace(stream);
|
||||
|
||||
if (stream.Take() != ':') {
|
||||
RAPIDJSON_PARSE_ERROR("There must be a colon after the name of object member", stream.Tell());
|
||||
break;
|
||||
}
|
||||
SkipWhitespace(stream);
|
||||
|
||||
ParseValue<parseFlags>(stream, handler);
|
||||
SkipWhitespace(stream);
|
||||
|
||||
++memberCount;
|
||||
|
||||
switch(stream.Take()) {
|
||||
case ',': SkipWhitespace(stream); break;
|
||||
case '}': handler.EndObject(memberCount); return;
|
||||
default: RAPIDJSON_PARSE_ERROR("Must be a comma or '}' after an object member", stream.Tell());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse array: [ value, ... ]
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseArray(Stream& stream, Handler& handler) {
|
||||
RAPIDJSON_ASSERT(stream.Peek() == '[');
|
||||
stream.Take(); // Skip '['
|
||||
handler.StartArray();
|
||||
SkipWhitespace(stream);
|
||||
|
||||
if (stream.Peek() == ']') {
|
||||
stream.Take();
|
||||
handler.EndArray(0); // empty array
|
||||
return;
|
||||
}
|
||||
|
||||
for (SizeType elementCount = 0;;) {
|
||||
ParseValue<parseFlags>(stream, handler);
|
||||
++elementCount;
|
||||
SkipWhitespace(stream);
|
||||
|
||||
switch (stream.Take()) {
|
||||
case ',': SkipWhitespace(stream); break;
|
||||
case ']': handler.EndArray(elementCount); return;
|
||||
default: RAPIDJSON_PARSE_ERROR("Must be a comma or ']' after an array element.", stream.Tell());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parses for null or NaN
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseNaNNull_(Stream& stream, Handler& handler) {
|
||||
RAPIDJSON_ASSERT(stream.Peek() == 'n');
|
||||
stream.Take();
|
||||
|
||||
if( stream.Peek() == 'a' && stream.Take() == 'a' && stream.Take() == 'n' )
|
||||
handler.Double( std::numeric_limits<double>::quiet_NaN() );
|
||||
else if (stream.Take() == 'u' && stream.Take() == 'l' && stream.Take() == 'l')
|
||||
handler.Null_();
|
||||
else
|
||||
RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
|
||||
}
|
||||
|
||||
// Parses for infinity
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseInfinity(Stream& stream, Handler& handler) {
|
||||
RAPIDJSON_ASSERT(stream.Peek() == 'i');
|
||||
stream.Take();
|
||||
|
||||
if (stream.Take() == 'n' && stream.Take() == 'f')
|
||||
handler.Double( std::numeric_limits<double>::infinity() );
|
||||
else
|
||||
RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
|
||||
}
|
||||
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseTrue(Stream& stream, Handler& handler) {
|
||||
RAPIDJSON_ASSERT(stream.Peek() == 't');
|
||||
stream.Take();
|
||||
|
||||
if (stream.Take() == 'r' && stream.Take() == 'u' && stream.Take() == 'e')
|
||||
handler.Bool_(true);
|
||||
else
|
||||
RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell());
|
||||
}
|
||||
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseFalse(Stream& stream, Handler& handler) {
|
||||
RAPIDJSON_ASSERT(stream.Peek() == 'f');
|
||||
stream.Take();
|
||||
|
||||
if (stream.Take() == 'a' && stream.Take() == 'l' && stream.Take() == 's' && stream.Take() == 'e')
|
||||
handler.Bool_(false);
|
||||
else
|
||||
RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
|
||||
}
|
||||
|
||||
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
||||
template<typename Stream>
|
||||
unsigned ParseHex4(Stream& stream) {
|
||||
Stream s = stream; // Use a local copy for optimization
|
||||
unsigned codepoint = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Ch c = s.Take();
|
||||
codepoint <<= 4;
|
||||
codepoint += c;
|
||||
if (c >= '0' && c <= '9')
|
||||
codepoint -= '0';
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
codepoint -= 'A' - 10;
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
codepoint -= 'a' - 10;
|
||||
else
|
||||
RAPIDJSON_PARSE_ERROR("Incorrect hex digit after \\u escape", s.Tell() - 1);
|
||||
}
|
||||
stream = s; // Restore stream
|
||||
return codepoint;
|
||||
}
|
||||
|
||||
// cereal Temporary until constexpr support is added in RTM
|
||||
#ifdef _MSC_VER
|
||||
template <class Ch>
|
||||
bool characterOk( Ch c )
|
||||
{
|
||||
return c < 256;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool characterOk<char>( char )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
// As part of a fix for GCC 4.7
|
||||
template <class T>
|
||||
static constexpr int to_int( T t ){ return t; }
|
||||
|
||||
template<class Ch>
|
||||
typename std::enable_if < to_int(std::numeric_limits<Ch>::max()) < to_int(256), bool>::type
|
||||
characterOk( Ch )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Ch>
|
||||
typename std::enable_if< to_int(std::numeric_limits<Ch>::max()) >= to_int(256), bool>::type
|
||||
characterOk(Ch c)
|
||||
{ return c < 256; }
|
||||
#endif
|
||||
|
||||
// Parse string, handling the prefix and suffix double quotes and escaping.
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseString(Stream& stream, Handler& handler) {
|
||||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
static const Ch escape[256] = {
|
||||
Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
|
||||
Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
|
||||
0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
|
||||
0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
|
||||
};
|
||||
#undef Z16
|
||||
|
||||
Stream s = stream; // Use a local copy for optimization
|
||||
RAPIDJSON_ASSERT(s.Peek() == '\"');
|
||||
s.Take(); // Skip '\"'
|
||||
Ch *head;
|
||||
SizeType len;
|
||||
if (parseFlags & kParseInsituFlag)
|
||||
head = s.PutBegin();
|
||||
else
|
||||
len = 0;
|
||||
|
||||
#define RAPIDJSON_PUT(x) \
|
||||
do { \
|
||||
if (parseFlags & kParseInsituFlag) \
|
||||
s.Put(x); \
|
||||
else { \
|
||||
*stack_.template Push<Ch>() = x; \
|
||||
++len; \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
for (;;) {
|
||||
Ch c = s.Take();
|
||||
if (c == '\\') { // Escape
|
||||
Ch e = s.Take();
|
||||
if ((sizeof(Ch) == 1 || characterOk(e)) && escape[(unsigned char)e])
|
||||
RAPIDJSON_PUT(escape[(unsigned char)e]);
|
||||
else if (e == 'u') { // Unicode
|
||||
unsigned codepoint = ParseHex4(s);
|
||||
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { // Handle UTF-16 surrogate pair
|
||||
if (s.Take() != '\\' || s.Take() != 'u') {
|
||||
RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", s.Tell() - 2);
|
||||
return;
|
||||
}
|
||||
unsigned codepoint2 = ParseHex4(s);
|
||||
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) {
|
||||
RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", s.Tell() - 2);
|
||||
return;
|
||||
}
|
||||
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
||||
}
|
||||
|
||||
Ch buffer[4];
|
||||
SizeType count = SizeType(Encoding::Encode(buffer, codepoint) - &buffer[0]);
|
||||
|
||||
if (parseFlags & kParseInsituFlag)
|
||||
for (SizeType i = 0; i < count; i++)
|
||||
s.Put(buffer[i]);
|
||||
else {
|
||||
memcpy(stack_.template Push<Ch>(count), buffer, count * sizeof(Ch));
|
||||
len += count;
|
||||
}
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_PARSE_ERROR("Unknown escape character", stream.Tell() - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (c == '"') { // Closing double quote
|
||||
if (parseFlags & kParseInsituFlag) {
|
||||
size_t length = s.PutEnd(head);
|
||||
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
|
||||
RAPIDJSON_PUT('\0'); // null-terminate the string
|
||||
handler.String(head, SizeType(length), false);
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_PUT('\0');
|
||||
handler.String(stack_.template Pop<Ch>(len), len - 1, true);
|
||||
}
|
||||
stream = s; // restore stream
|
||||
return;
|
||||
}
|
||||
else if (c == '\0') {
|
||||
RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", stream.Tell() - 1);
|
||||
return;
|
||||
}
|
||||
else if ((unsigned)c < 0x20) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||
RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", stream.Tell() - 1);
|
||||
return;
|
||||
}
|
||||
else
|
||||
RAPIDJSON_PUT(c); // Normal character, just copy
|
||||
}
|
||||
#undef RAPIDJSON_PUT
|
||||
}
|
||||
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseNumber(Stream& stream, Handler& handler) {
|
||||
Stream s = stream; // Local copy for optimization
|
||||
|
||||
// Parse minus
|
||||
bool minus = false;
|
||||
if (s.Peek() == '-') {
|
||||
minus = true;
|
||||
s.Take();
|
||||
}
|
||||
|
||||
// Parse int: zero / ( digit1-9 *DIGIT )
|
||||
unsigned i;
|
||||
bool try64bit = false;
|
||||
if (s.Peek() == '0') {
|
||||
i = 0;
|
||||
s.Take();
|
||||
}
|
||||
else if (s.Peek() >= '1' && s.Peek() <= '9') {
|
||||
i = s.Take() - '0';
|
||||
|
||||
if (minus)
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i >= 214748364) { // 2^31 = 2147483648
|
||||
if (i != 214748364 || s.Peek() > '8') {
|
||||
try64bit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i = i * 10 + (s.Take() - '0');
|
||||
}
|
||||
else
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i >= 429496729) { // 2^32 - 1 = 4294967295
|
||||
if (i != 429496729 || s.Peek() > '5') {
|
||||
try64bit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i = i * 10 + (s.Take() - '0');
|
||||
}
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_PARSE_ERROR("Expect a value here.", stream.Tell());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse 64bit int
|
||||
uint64_t i64 = 0;
|
||||
bool useDouble = false;
|
||||
if (try64bit) {
|
||||
i64 = i;
|
||||
if (minus)
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i64 >= 922337203685477580uLL) // 2^63 = 9223372036854775808
|
||||
if (i64 != 922337203685477580uLL || s.Peek() > '8') {
|
||||
useDouble = true;
|
||||
break;
|
||||
}
|
||||
i64 = i64 * 10 + (s.Take() - '0');
|
||||
}
|
||||
else
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i64 >= 1844674407370955161uLL) // 2^64 - 1 = 18446744073709551615
|
||||
if (i64 != 1844674407370955161uLL || s.Peek() > '5') {
|
||||
useDouble = true;
|
||||
break;
|
||||
}
|
||||
i64 = i64 * 10 + (s.Take() - '0');
|
||||
}
|
||||
}
|
||||
|
||||
// Force double for big integer
|
||||
double d = 0.0;
|
||||
if (useDouble) {
|
||||
d = (double)i64;
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (d >= 1E307) {
|
||||
RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
|
||||
return;
|
||||
}
|
||||
d = d * 10 + (s.Take() - '0');
|
||||
}
|
||||
}
|
||||
|
||||
// Parse frac = decimal-point 1*DIGIT
|
||||
int expFrac = 0;
|
||||
if (s.Peek() == '.') {
|
||||
if (!useDouble) {
|
||||
d = try64bit ? (double)i64 : (double)i;
|
||||
useDouble = true;
|
||||
}
|
||||
s.Take();
|
||||
|
||||
if (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
d = d * 10 + (s.Take() - '0');
|
||||
--expFrac;
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_PARSE_ERROR("At least one digit in fraction part", stream.Tell());
|
||||
return;
|
||||
}
|
||||
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (expFrac > -20) {
|
||||
d = d * 10 + (s.Peek() - '0');
|
||||
--expFrac;
|
||||
}
|
||||
s.Take();
|
||||
}
|
||||
}
|
||||
|
||||
// Parse exp = e [ minus / plus ] 1*DIGIT
|
||||
int exp = 0;
|
||||
if (s.Peek() == 'e' || s.Peek() == 'E') {
|
||||
if (!useDouble) {
|
||||
d = try64bit ? (double)i64 : (double)i;
|
||||
useDouble = true;
|
||||
}
|
||||
s.Take();
|
||||
|
||||
bool expMinus = false;
|
||||
if (s.Peek() == '+')
|
||||
s.Take();
|
||||
else if (s.Peek() == '-') {
|
||||
s.Take();
|
||||
expMinus = true;
|
||||
}
|
||||
|
||||
if (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
exp = s.Take() - '0';
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
exp = exp * 10 + (s.Take() - '0');
|
||||
if (exp > 308) {
|
||||
// Attempt denormalized construction
|
||||
std::stringstream ss;
|
||||
ss.precision( std::numeric_limits<double>::max_digits10 );
|
||||
ss << d * internal::Pow10(expFrac) << 'e' << (expMinus ? '-' : '+') << exp;
|
||||
|
||||
double dd;
|
||||
ss >> dd;
|
||||
|
||||
if( std::fpclassify( dd ) == FP_SUBNORMAL )
|
||||
handler.Double( dd );
|
||||
else
|
||||
RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_PARSE_ERROR("At least one digit in exponent", s.Tell());
|
||||
return;
|
||||
}
|
||||
|
||||
if (expMinus)
|
||||
exp = -exp;
|
||||
}
|
||||
|
||||
// Finish parsing, call event according to the type of number.
|
||||
if (useDouble) {
|
||||
d *= internal::Pow10(exp + expFrac);
|
||||
handler.Double(minus ? -d : d);
|
||||
}
|
||||
else {
|
||||
if (try64bit) {
|
||||
if (minus)
|
||||
handler.Int64(-(int64_t)i64);
|
||||
else
|
||||
handler.Uint64(i64);
|
||||
}
|
||||
else {
|
||||
if (minus)
|
||||
handler.Int(-(int)i);
|
||||
else
|
||||
handler.Uint(i);
|
||||
}
|
||||
}
|
||||
|
||||
stream = s; // restore stream
|
||||
}
|
||||
|
||||
// Parse any JSON value
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseValue(Stream& stream, Handler& handler) {
|
||||
switch (stream.Peek()) {
|
||||
case 'n': ParseNaNNull_ <parseFlags>(stream, handler); break;
|
||||
case 'i': ParseInfinity <parseFlags>(stream, handler); break;
|
||||
case 't': ParseTrue <parseFlags>(stream, handler); break;
|
||||
case 'f': ParseFalse <parseFlags>(stream, handler); break;
|
||||
case '"': ParseString <parseFlags>(stream, handler); break;
|
||||
case '{': ParseObject <parseFlags>(stream, handler); break;
|
||||
case '[': ParseArray <parseFlags>(stream, handler); break;
|
||||
default : ParseNumber <parseFlags>(stream, handler);
|
||||
}
|
||||
}
|
||||
|
||||
static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
|
||||
internal::Stack<Allocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
|
||||
jmp_buf jmpbuf_; //!< setjmp buffer for fast exit from nested parsing function calls.
|
||||
const char* parseError_;
|
||||
size_t errorOffset_;
|
||||
}; // class GenericReader
|
||||
|
||||
//! Reader with UTF8 encoding and default allocator.
|
||||
typedef GenericReader<UTF8<> > Reader;
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_READER_H_
|
||||
49
libs/cereal/cereal/external/rapidjson/stringbuffer.h
vendored
Normal file
49
libs/cereal/cereal/external/rapidjson/stringbuffer.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef RAPIDJSON_STRINGBUFFER_H_
|
||||
#define RAPIDJSON_STRINGBUFFER_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Represents an in-memory output stream.
|
||||
/*!
|
||||
\tparam Encoding Encoding of the stream.
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\implements Stream
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
struct GenericStringBuffer {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
|
||||
const char* GetString() const {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.template Pop<Ch>(1);
|
||||
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
size_t Size() const { return stack_.GetSize(); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
};
|
||||
|
||||
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
||||
memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_STRINGBUFFER_H_
|
||||
330
libs/cereal/cereal/external/rapidjson/writer.h
vendored
Normal file
330
libs/cereal/cereal/external/rapidjson/writer.h
vendored
Normal file
@ -0,0 +1,330 @@
|
||||
#ifndef RAPIDJSON_WRITER_H_
|
||||
#define RAPIDJSON_WRITER_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/stack.h"
|
||||
#include "internal/strfunc.h"
|
||||
#include <cstdio> // snprintf() or _sprintf_s()
|
||||
#include <new> // placement new
|
||||
#include <limits>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! JSON writer
|
||||
/*! Writer implements the concept Handler.
|
||||
It generates JSON text by events to an output stream.
|
||||
|
||||
User may programmatically calls the functions of a writer to generate JSON text.
|
||||
|
||||
On the other side, a writer can also be passed to objects that generates events,
|
||||
|
||||
for example Reader::Parse() and Document::Accept().
|
||||
|
||||
\tparam Stream Type of ouptut stream.
|
||||
\tparam Encoding Encoding of both source strings and output.
|
||||
\implements Handler
|
||||
*/
|
||||
template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
|
||||
class Writer {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
Writer(Stream& stream, int precision = 20, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
stream_(stream), level_stack_(allocator, levelDepth * sizeof(Level))
|
||||
{
|
||||
#if _MSC_VER
|
||||
(void) sprintf_s(double_format, sizeof(double_format), "%%0.%dg", precision);
|
||||
(void) sprintf_s( long_double_format, sizeof( long_double_format ), "%%0.%dLg", precision );
|
||||
#else
|
||||
(void) snprintf(double_format, sizeof(double_format), "%%0.%dg", precision);
|
||||
(void) snprintf( long_double_format, sizeof( long_double_format ), "%%0.%dLg", precision );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
char double_format[32];
|
||||
char long_double_format[32];
|
||||
public:
|
||||
|
||||
//@name Implementation of Handler
|
||||
//@{
|
||||
|
||||
Writer& Null_() { Prefix(kNull_Type); WriteNull_(); return *this; }
|
||||
Writer& Bool_(bool b) { Prefix(b ? kTrueType : kFalseType); WriteBool_(b); return *this; }
|
||||
Writer& Int(int i) { Prefix(kNumberType); WriteInt(i); return *this; }
|
||||
Writer& Uint(unsigned u) { Prefix(kNumberType); WriteUint(u); return *this; }
|
||||
Writer& Int64(int64_t i64) { Prefix(kNumberType); WriteInt64(i64); return *this; }
|
||||
Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64); return *this; }
|
||||
Writer& Double(double d) { Prefix(kNumberType); WriteDouble(d); return *this; }
|
||||
Writer& LongDouble(long double d) { Prefix(kNumberType); WriteLongDouble(d); return *this; }
|
||||
Writer& LongLong(long long d) { Prefix(kNumberType); WriteLongLong(d); return *this; }
|
||||
Writer& ULongLong(unsigned long long d) { Prefix(kNumberType); WriteULongLong(d); return *this; }
|
||||
|
||||
Writer& String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
Prefix(kStringType);
|
||||
WriteString(str, length);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Writer& StartObject() {
|
||||
Prefix(kObjectType);
|
||||
new (level_stack_.template Push<Level>()) Level(false);
|
||||
WriteStartObject();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Writer& EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
|
||||
level_stack_.template Pop<Level>(1);
|
||||
WriteEndObject();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Writer& StartArray() {
|
||||
Prefix(kArrayType);
|
||||
new (level_stack_.template Push<Level>()) Level(true);
|
||||
WriteStartArray();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Writer& EndArray(SizeType elementCount = 0) {
|
||||
(void)elementCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
|
||||
level_stack_.template Pop<Level>(1);
|
||||
WriteEndArray();
|
||||
return *this;
|
||||
}
|
||||
//@}
|
||||
|
||||
//! Simpler but slower overload.
|
||||
Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
|
||||
protected:
|
||||
//! Information for each nested level
|
||||
struct Level {
|
||||
Level(bool inArray_) : inArray(inArray_), valueCount(0) {}
|
||||
bool inArray; //!< true if in array, otherwise in object
|
||||
size_t valueCount; //!< number of values in this level
|
||||
};
|
||||
|
||||
static const size_t kDefaultLevelDepth = 32;
|
||||
|
||||
void WriteNull_() {
|
||||
stream_.Put('n'); stream_.Put('u'); stream_.Put('l'); stream_.Put('l');
|
||||
}
|
||||
|
||||
void WriteBool_(bool b) {
|
||||
if (b) {
|
||||
stream_.Put('t'); stream_.Put('r'); stream_.Put('u'); stream_.Put('e');
|
||||
}
|
||||
else {
|
||||
stream_.Put('f'); stream_.Put('a'); stream_.Put('l'); stream_.Put('s'); stream_.Put('e');
|
||||
}
|
||||
}
|
||||
|
||||
void WriteInt(int i) {
|
||||
if (i < 0) {
|
||||
stream_.Put('-');
|
||||
i = -i;
|
||||
}
|
||||
WriteUint((unsigned)i);
|
||||
}
|
||||
|
||||
void WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = (u % 10) + '0';
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
stream_.Put(*p);
|
||||
} while (p != buffer);
|
||||
}
|
||||
|
||||
void WriteInt64(int64_t i64) {
|
||||
if (i64 < 0) {
|
||||
stream_.Put('-');
|
||||
i64 = -i64;
|
||||
}
|
||||
WriteUint64((uint64_t)i64);
|
||||
}
|
||||
|
||||
void WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = char(u64 % 10) + '0';
|
||||
u64 /= 10;
|
||||
} while (u64 > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
stream_.Put(*p);
|
||||
} while (p != buffer);
|
||||
}
|
||||
|
||||
// cereal Temporary until constexpr support is added in RTM
|
||||
#ifdef _MSC_VER
|
||||
template <class Ch>
|
||||
bool characterOk( Ch c )
|
||||
{
|
||||
return c < 256;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool characterOk<char>( char )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
// As part of a fix for GCC 4.7
|
||||
template <class T>
|
||||
static constexpr int to_int( T t ){ return t; }
|
||||
|
||||
template<class Ch>
|
||||
typename std::enable_if < to_int(std::numeric_limits<Ch>::max()) < to_int(256), bool>::type
|
||||
characterOk( Ch )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Ch>
|
||||
typename std::enable_if< to_int(std::numeric_limits<Ch>::max()) >= to_int(256), bool>::type
|
||||
characterOk(Ch c)
|
||||
{ return c < 256; }
|
||||
#endif
|
||||
|
||||
//! \todo Optimization with custom double-to-string converter.
|
||||
void WriteDouble(double d) {
|
||||
char buffer[100];
|
||||
#if _MSC_VER
|
||||
int ret = sprintf_s(buffer, sizeof(buffer), double_format, d);
|
||||
#else
|
||||
int ret = snprintf(buffer, sizeof(buffer), double_format, d);
|
||||
#endif
|
||||
RAPIDJSON_ASSERT(ret >= 1);
|
||||
for (int i = 0; i < ret; i++)
|
||||
stream_.Put(buffer[i]);
|
||||
}
|
||||
|
||||
void WriteLongDouble(long double d) {
|
||||
char buffer[256];
|
||||
#if _MSC_VER
|
||||
int ret = sprintf_s(buffer, sizeof(buffer), long_double_format, d);
|
||||
#else
|
||||
int ret = snprintf(buffer, sizeof(buffer), long_double_format, d);
|
||||
#endif
|
||||
RAPIDJSON_ASSERT(ret >= 1);
|
||||
for (int i = 0; i < ret; i++)
|
||||
stream_.Put(buffer[i]);
|
||||
}
|
||||
|
||||
void WriteLongLong(long long d) {
|
||||
char buffer[256];
|
||||
#if _MSC_VER
|
||||
int ret = sprintf_s(buffer, sizeof(buffer), "%lld", d);
|
||||
#else
|
||||
int ret = snprintf(buffer, sizeof(buffer), "%lld", d);
|
||||
#endif
|
||||
RAPIDJSON_ASSERT(ret >= 1);
|
||||
for (int i = 0; i < ret; i++)
|
||||
stream_.Put(buffer[i]);
|
||||
}
|
||||
|
||||
void WriteULongLong(unsigned long long d) {
|
||||
char buffer[256];
|
||||
#if _MSC_VER
|
||||
int ret = sprintf_s(buffer, sizeof(buffer), "%llu", d);
|
||||
#else
|
||||
int ret = snprintf(buffer, sizeof(buffer), "%llu", d);
|
||||
#endif
|
||||
RAPIDJSON_ASSERT(ret >= 1);
|
||||
for (int i = 0; i < ret; i++)
|
||||
stream_.Put(buffer[i]);
|
||||
}
|
||||
|
||||
void WriteString(const Ch* str, SizeType length) {
|
||||
static const char hexDigits[] = "0123456789ABCDEF";
|
||||
static const char escape[256] = {
|
||||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
|
||||
Z16, Z16, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
|
||||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
|
||||
#undef Z16
|
||||
};
|
||||
|
||||
stream_.Put('\"');
|
||||
for (const Ch* p = str; p != str + length; ++p) {
|
||||
if ((sizeof(Ch) == 1 || characterOk(*p)) && escape[(unsigned char)*p]) {
|
||||
//if ((sizeof(Ch) == 1 || *p < 256) && escape[(unsigned char)*p]) {
|
||||
stream_.Put('\\');
|
||||
stream_.Put(escape[(unsigned char)*p]);
|
||||
if (escape[(unsigned char)*p] == 'u') {
|
||||
stream_.Put('0');
|
||||
stream_.Put('0');
|
||||
stream_.Put(hexDigits[(*p) >> 4]);
|
||||
stream_.Put(hexDigits[(*p) & 0xF]);
|
||||
}
|
||||
}
|
||||
else
|
||||
stream_.Put(*p);
|
||||
}
|
||||
stream_.Put('\"');
|
||||
}
|
||||
|
||||
void WriteStartObject() { stream_.Put('{'); }
|
||||
void WriteEndObject() { stream_.Put('}'); }
|
||||
void WriteStartArray() { stream_.Put('['); }
|
||||
void WriteEndArray() { stream_.Put(']'); }
|
||||
|
||||
void Prefix(Type type) {
|
||||
(void)type;
|
||||
if (level_stack_.GetSize() != 0) { // this value is not at root
|
||||
Level* level = level_stack_.template Top<Level>();
|
||||
if (level->valueCount > 0) {
|
||||
if (level->inArray)
|
||||
stream_.Put(','); // add comma if it is not the first element in array
|
||||
else // in object
|
||||
stream_.Put((level->valueCount % 2 == 0) ? ',' : ':');
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else
|
||||
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
|
||||
}
|
||||
|
||||
Stream& stream_;
|
||||
internal::Stack<Allocator> level_stack_;
|
||||
|
||||
private:
|
||||
// Prohibit assignment for VC C4512 warning
|
||||
Writer& operator=(const Writer& w);
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
52
libs/cereal/cereal/external/rapidxml/license.txt
vendored
Normal file
52
libs/cereal/cereal/external/rapidxml/license.txt
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
Use of this software is granted under one of the following two licenses,
|
||||
to be chosen freely by the user.
|
||||
|
||||
1. Boost Software License - Version 1.0 - August 17th, 2003
|
||||
===============================================================================
|
||||
|
||||
Copyright (c) 2006, 2007 Marcin Kalicinski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
2. The MIT License
|
||||
===============================================================================
|
||||
|
||||
Copyright (c) 2006, 2007 Marcin Kalicinski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
406
libs/cereal/cereal/external/rapidxml/manual.html
vendored
Normal file
406
libs/cereal/cereal/external/rapidxml/manual.html
vendored
Normal file
File diff suppressed because one or more lines are too long
2618
libs/cereal/cereal/external/rapidxml/rapidxml.hpp
vendored
Normal file
2618
libs/cereal/cereal/external/rapidxml/rapidxml.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
173
libs/cereal/cereal/external/rapidxml/rapidxml_iterators.hpp
vendored
Normal file
173
libs/cereal/cereal/external/rapidxml/rapidxml_iterators.hpp
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
#define RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Iterator of child nodes of xml_node
|
||||
template<class Ch>
|
||||
class node_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_node<Ch> value_type;
|
||||
typedef typename xml_node<Ch> &reference;
|
||||
typedef typename xml_node<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
node_iterator()
|
||||
: m_node(0)
|
||||
{
|
||||
}
|
||||
|
||||
node_iterator(xml_node<Ch> *node)
|
||||
: m_node(node->first_node())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_node);
|
||||
return *m_node;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_node);
|
||||
return m_node;
|
||||
}
|
||||
|
||||
node_iterator& operator++()
|
||||
{
|
||||
assert(m_node);
|
||||
m_node = m_node->next_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator++(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
node_iterator& operator--()
|
||||
{
|
||||
assert(m_node && m_node->previous_sibling());
|
||||
m_node = m_node->previous_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator--(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node == rhs.m_node;
|
||||
}
|
||||
|
||||
bool operator !=(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node != rhs.m_node;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_node<Ch> *m_node;
|
||||
|
||||
};
|
||||
|
||||
//! Iterator of child attributes of xml_node
|
||||
template<class Ch>
|
||||
class attribute_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_attribute<Ch> value_type;
|
||||
typedef typename xml_attribute<Ch> &reference;
|
||||
typedef typename xml_attribute<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
attribute_iterator()
|
||||
: m_attribute(0)
|
||||
{
|
||||
}
|
||||
|
||||
attribute_iterator(xml_node<Ch> *node)
|
||||
: m_attribute(node->first_attribute())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return *m_attribute;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return m_attribute;
|
||||
}
|
||||
|
||||
attribute_iterator& operator++()
|
||||
{
|
||||
assert(m_attribute);
|
||||
m_attribute = m_attribute->next_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator++(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
attribute_iterator& operator--()
|
||||
{
|
||||
assert(m_attribute && m_attribute->previous_attribute());
|
||||
m_attribute = m_attribute->previous_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator--(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute == rhs.m_attribute;
|
||||
}
|
||||
|
||||
bool operator !=(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute != rhs.m_attribute;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_attribute<Ch> *m_attribute;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
424
libs/cereal/cereal/external/rapidxml/rapidxml_print.hpp
vendored
Normal file
424
libs/cereal/cereal/external/rapidxml/rapidxml_print.hpp
vendored
Normal file
@ -0,0 +1,424 @@
|
||||
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#define RAPIDXML_PRINT_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
// Only include streams if not disabled
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Printing flags
|
||||
|
||||
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Internal
|
||||
|
||||
//! \cond internal
|
||||
namespace internal
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal character operations
|
||||
|
||||
// Copy characters from given range to given output iterator
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
*out++ = *begin++;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Copy characters from given range to given output iterator and expand
|
||||
// characters into references (< > ' " &)
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
if (*begin == noexpand)
|
||||
{
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*begin)
|
||||
{
|
||||
case Ch('<'):
|
||||
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('>'):
|
||||
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('\''):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('"'):
|
||||
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('&'):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
|
||||
break;
|
||||
default:
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
}
|
||||
++begin; // Step to next character
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Fill given output iterator with repetitions of the same character
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt fill_chars(OutIt out, int n, Ch ch)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Find character
|
||||
template<class Ch, Ch ch>
|
||||
inline bool find_char(const Ch *begin, const Ch *end)
|
||||
{
|
||||
while (begin != end)
|
||||
if (*begin++ == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal printing operations
|
||||
|
||||
// Print node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
// Print children of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
|
||||
out = print_node(out, child, flags, indent);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print attributes of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int /*flags*/)
|
||||
{
|
||||
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
|
||||
{
|
||||
if (attribute->name() && attribute->value())
|
||||
{
|
||||
// Print attribute name
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
|
||||
*out = Ch('='), ++out;
|
||||
// Print attribute value using appropriate quote type
|
||||
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
|
||||
{
|
||||
*out = Ch('\''), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
|
||||
*out = Ch('\''), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = Ch('"'), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
|
||||
*out = Ch('"'), ++out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_data);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_cdata);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'); ++out;
|
||||
*out = Ch('!'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
*out = Ch('C'); ++out;
|
||||
*out = Ch('D'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('T'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch('>'); ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print element node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_element);
|
||||
|
||||
// Print element name and attributes, if any
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// If node is childless
|
||||
if (node->value_size() == 0 && !node->first_node())
|
||||
{
|
||||
// Print childless node tag ending
|
||||
*out = Ch('/'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print normal node tag ending
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
// Test if node contains a single data node only (and no other nodes)
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
if (!child)
|
||||
{
|
||||
// If node has no children, only print its value without indenting
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
}
|
||||
else if (child->next_sibling() == 0 && child->type() == node_data)
|
||||
{
|
||||
// If node has a sole data child, only print its value without indenting
|
||||
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print all children with full indenting
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
out = print_children(out, node, flags, indent + 1);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
}
|
||||
|
||||
// Print node end
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('/'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print declaration node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print declaration start
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('x'), ++out;
|
||||
*out = Ch('m'), ++out;
|
||||
*out = Ch('l'), ++out;
|
||||
|
||||
// Print attributes
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// Print declaration end
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print comment node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_comment);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print doctype node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_doctype);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('D'), ++out;
|
||||
*out = Ch('O'), ++out;
|
||||
*out = Ch('C'), ++out;
|
||||
*out = Ch('T'), ++out;
|
||||
*out = Ch('Y'), ++out;
|
||||
*out = Ch('P'), ++out;
|
||||
*out = Ch('E'), ++out;
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print pi node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_pi);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print proper node type
|
||||
switch (node->type())
|
||||
{
|
||||
|
||||
// Document
|
||||
case node_document:
|
||||
out = print_children(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Element
|
||||
case node_element:
|
||||
out = print_element_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Data
|
||||
case node_data:
|
||||
out = print_data_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// CDATA
|
||||
case node_cdata:
|
||||
out = print_cdata_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Declaration
|
||||
case node_declaration:
|
||||
out = print_declaration_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Comment
|
||||
case node_comment:
|
||||
out = print_comment_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Doctype
|
||||
case node_doctype:
|
||||
out = print_doctype_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Pi
|
||||
case node_pi:
|
||||
out = print_pi_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Unknown
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
// If indenting not disabled, add line break after node
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
|
||||
// Return modified iterator
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
//! \endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Printing
|
||||
|
||||
//! Prints XML to given output iterator.
|
||||
//! \param out Output iterator to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output iterator pointing to position immediately after last character of printed text.
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
return internal::print_node(out, &node, flags, 0);
|
||||
}
|
||||
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
|
||||
//! Prints XML to given output stream.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
print(std::ostream_iterator<Ch>(out), node, flags);
|
||||
return out;
|
||||
}
|
||||
|
||||
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
|
||||
{
|
||||
return print(out, node);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
121
libs/cereal/cereal/external/rapidxml/rapidxml_utils.hpp
vendored
Normal file
121
libs/cereal/cereal/external/rapidxml/rapidxml_utils.hpp
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
|
||||
#define RAPIDXML_UTILS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Represents data loaded from a file
|
||||
template<class Ch = char>
|
||||
class file
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
|
||||
//! \param filename Filename to load.
|
||||
file(const char *filename)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Open stream
|
||||
basic_ifstream<Ch> stream(filename, ios::binary);
|
||||
if (!stream)
|
||||
throw runtime_error(string("cannot open file ") + filename);
|
||||
stream.unsetf(ios::skipws);
|
||||
|
||||
// Determine stream size
|
||||
stream.seekg(0, ios::end);
|
||||
size_t size = stream.tellg();
|
||||
stream.seekg(0);
|
||||
|
||||
// Load data and add terminating 0
|
||||
m_data.resize(size + 1);
|
||||
stream.read(&m_data.front(), static_cast<streamsize>(size));
|
||||
m_data[size] = 0;
|
||||
}
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor
|
||||
//! \param stream Stream to load from
|
||||
file(std::basic_istream<Ch> &stream)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Load data and add terminating 0
|
||||
stream.unsetf(ios::skipws);
|
||||
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
|
||||
if (stream.fail() || stream.bad())
|
||||
throw runtime_error("error reading stream");
|
||||
m_data.push_back(0);
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
Ch *data()
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
const Ch *data() const
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data size.
|
||||
//! \return Size of file data, in characters.
|
||||
std::size_t size() const
|
||||
{
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Ch> m_data; // File data
|
||||
|
||||
};
|
||||
|
||||
//! Counts children of node. Time complexity is O(n).
|
||||
//! \return Number of children of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_children(xml_node<Ch> *node)
|
||||
{
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
std::size_t count = 0;
|
||||
while (child)
|
||||
{
|
||||
++count;
|
||||
child = child->next_sibling();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//! Counts attributes of node. Time complexity is O(n).
|
||||
//! \return Number of attributes of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_attributes(xml_node<Ch> *node)
|
||||
{
|
||||
xml_attribute<Ch> *attr = node->first_attribute();
|
||||
std::size_t count = 0;
|
||||
while (attr)
|
||||
{
|
||||
++count;
|
||||
attr = attr->next_attribute();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
82
libs/cereal/cereal/macros.hpp
Normal file
82
libs/cereal/cereal/macros.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
/*! \file macros.hpp
|
||||
\brief Preprocessor macros that can customise the cereal library
|
||||
|
||||
By default, cereal looks for serialization functions with very
|
||||
specific names, that is: serialize, load, save, load_minimal,
|
||||
or save_minimal.
|
||||
|
||||
This file allows an advanced user to change these names to conform
|
||||
to some other style or preference. This is implemented using
|
||||
preprocessor macros.
|
||||
|
||||
As a result of this, in internal cereal code you will see macros
|
||||
used for these function names. In user code, you should name
|
||||
the functions like you normally would and not use the macros
|
||||
to improve readability.
|
||||
\ingroup utility */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
|
||||
#ifndef CEREAL_MACROS_HPP_
|
||||
#define CEREAL_MACROS_HPP_
|
||||
|
||||
#ifndef CEREAL_SERIALIZE_FUNCTION_NAME
|
||||
//! The serialization/deserialization function name to search for.
|
||||
/*! You can define @c CEREAL_SERIALIZE_FUNCTION_NAME to be different assuming
|
||||
you do so before this file is included. */
|
||||
#define CEREAL_SERIALIZE_FUNCTION_NAME serialize
|
||||
#endif // CEREAL_SERIALIZE_FUNCTION_NAME
|
||||
|
||||
#ifndef CEREAL_LOAD_FUNCTION_NAME
|
||||
//! The deserialization (load) function name to search for.
|
||||
/*! You can define @c CEREAL_LOAD_FUNCTION_NAME to be different assuming you do so
|
||||
before this file is included. */
|
||||
#define CEREAL_LOAD_FUNCTION_NAME load
|
||||
#endif // CEREAL_LOAD_FUNCTION_NAME
|
||||
|
||||
#ifndef CEREAL_SAVE_FUNCTION_NAME
|
||||
//! The serialization (save) function name to search for.
|
||||
/*! You can define @c CEREAL_SAVE_FUNCTION_NAME to be different assuming you do so
|
||||
before this file is included. */
|
||||
#define CEREAL_SAVE_FUNCTION_NAME save
|
||||
#endif // CEREAL_SAVE_FUNCTION_NAME
|
||||
|
||||
#ifndef CEREAL_LOAD_MINIMAL_FUNCTION_NAME
|
||||
//! The deserialization (load_minimal) function name to search for.
|
||||
/*! You can define @c CEREAL_LOAD_MINIMAL_FUNCTION_NAME to be different assuming you do so
|
||||
before this file is included. */
|
||||
#define CEREAL_LOAD_MINIMAL_FUNCTION_NAME load_minimal
|
||||
#endif // CEREAL_LOAD_MINIMAL_FUNCTION_NAME
|
||||
|
||||
#ifndef CEREAL_SAVE_MINIMAL_FUNCTION_NAME
|
||||
//! The serialization (save_minimal) function name to search for.
|
||||
/*! You can define @c CEREAL_SAVE_MINIMAL_FUNCTION_NAME to be different assuming you do so
|
||||
before this file is included. */
|
||||
#define CEREAL_SAVE_MINIMAL_FUNCTION_NAME save_minimal
|
||||
#endif // CEREAL_SAVE_MINIMAL_FUNCTION_NAME
|
||||
|
||||
#endif // CEREAL_MACROS_HPP_
|
||||
79
libs/cereal/cereal/types/array.hpp
Normal file
79
libs/cereal/cereal/types/array.hpp
Normal file
@ -0,0 +1,79 @@
|
||||
/*! \file array.hpp
|
||||
\brief Support for types found in \<array\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_ARRAY_HPP_
|
||||
#define CEREAL_TYPES_ARRAY_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving for std::array primitive types
|
||||
//! using binary serialization, if supported
|
||||
template <class Archive, class T, size_t N> inline
|
||||
typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::array<T, N> const & array )
|
||||
{
|
||||
ar( binary_data( array.data(), sizeof(array) ) );
|
||||
}
|
||||
|
||||
//! Loading for std::array primitive types
|
||||
//! using binary serialization, if supported
|
||||
template <class Archive, class T, size_t N> inline
|
||||
typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::array<T, N> & array )
|
||||
{
|
||||
ar( binary_data( array.data(), sizeof(array) ) );
|
||||
}
|
||||
|
||||
//! Saving for std::array all other types
|
||||
template <class Archive, class T, size_t N> inline
|
||||
typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::array<T, N> const & array )
|
||||
{
|
||||
for( auto const & i : array )
|
||||
ar( i );
|
||||
}
|
||||
|
||||
//! Loading for std::array all other types
|
||||
template <class Archive, class T, size_t N> inline
|
||||
typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::array<T, N> & array )
|
||||
{
|
||||
for( auto & i : array )
|
||||
ar( i );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_ARRAY_HPP_
|
||||
164
libs/cereal/cereal/types/base_class.hpp
Normal file
164
libs/cereal/cereal/types/base_class.hpp
Normal file
@ -0,0 +1,164 @@
|
||||
/*! \file base_class.hpp
|
||||
\brief Support for base classes (virtual and non-virtual)
|
||||
\ingroup OtherTypes */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_BASE_CLASS_HPP_
|
||||
#define CEREAL_TYPES_BASE_CLASS_HPP_
|
||||
|
||||
#include <cereal/details/traits.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Casts a derived class to its non-virtual base class in a way that safely supports abstract classes
|
||||
/*! This should be used in cases when a derived type needs to serialize its base type. This is better than directly
|
||||
using static_cast, as it allows for serialization of pure virtual (abstract) base classes.
|
||||
|
||||
\sa virtual_base_class
|
||||
|
||||
@code{.cpp}
|
||||
struct MyBase
|
||||
{
|
||||
int x;
|
||||
|
||||
virtual void foo() = 0;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( x );
|
||||
}
|
||||
};
|
||||
|
||||
struct MyDerived : public MyBase //<-- Note non-virtual inheritance
|
||||
{
|
||||
int y;
|
||||
|
||||
virtual void foo() {};
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( cereal::base_class<MyBase>(this) );
|
||||
ar( y );
|
||||
}
|
||||
};
|
||||
@endcode */
|
||||
template<class Base>
|
||||
struct base_class : private traits::detail::BaseCastBase
|
||||
{
|
||||
template<class Derived>
|
||||
base_class(Derived const * derived) :
|
||||
base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
|
||||
{ static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" ); }
|
||||
|
||||
Base * base_ptr;
|
||||
};
|
||||
|
||||
//! Casts a derived class to its virtual base class in a way that allows cereal to track inheritance
|
||||
/*! This should be used in cases when a derived type features virtual inheritance from some
|
||||
base type. This allows cereal to track the inheritance and to avoid making duplicate copies
|
||||
during serialization.
|
||||
|
||||
It is safe to use virtual_base_class in all circumstances for serializing base classes, even in cases
|
||||
where virtual inheritance does not take place, though it may be slightly faster to utilize
|
||||
cereal::base_class<> if you do not need to worry about virtual inheritance.
|
||||
|
||||
\sa base_class
|
||||
|
||||
@code{.cpp}
|
||||
struct MyBase
|
||||
{
|
||||
int x;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( x );
|
||||
}
|
||||
};
|
||||
|
||||
struct MyLeft : virtual MyBase //<-- Note the virtual inheritance
|
||||
{
|
||||
int y;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( cereal::virtual_base_class<MyBase>( this ) );
|
||||
ar( y );
|
||||
}
|
||||
};
|
||||
|
||||
struct MyRight : virtual MyBase
|
||||
{
|
||||
int z;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( cereal::virtual_base_clas<MyBase>( this ) );
|
||||
ar( z );
|
||||
}
|
||||
};
|
||||
|
||||
// diamond virtual inheritance; contains one copy of each base class
|
||||
struct MyDerived : virtual MyLeft, virtual MyRight
|
||||
{
|
||||
int a;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( cereal::virtual_base_class<MyLeft>( this ) ); // safely serialize data members in MyLeft
|
||||
ar( cereal::virtual_base_class<MyRight>( this ) ); // safely serialize data members in MyRight
|
||||
ar( a );
|
||||
|
||||
// Because we used virtual_base_class, cereal will ensure that only one instance of MyBase is
|
||||
// serialized as we traverse the inheritance heirarchy. This means that there will be one copy
|
||||
// each of the variables x, y, z, and a
|
||||
|
||||
// If we had chosen to use static_cast<> instead, cereal would perform no tracking and
|
||||
// assume that every base class should be serialized (in this case leading to a duplicate
|
||||
// serialization of MyBase due to diamond inheritance
|
||||
};
|
||||
}
|
||||
@endcode */
|
||||
template<class Base>
|
||||
struct virtual_base_class : private traits::detail::BaseCastBase
|
||||
{
|
||||
template<class Derived>
|
||||
virtual_base_class(Derived const * derived) :
|
||||
base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
|
||||
{ static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" ); }
|
||||
|
||||
Base * base_ptr;
|
||||
};
|
||||
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_BASE_CLASS_HPP_
|
||||
112
libs/cereal/cereal/types/bitset.hpp
Normal file
112
libs/cereal/cereal/types/bitset.hpp
Normal file
@ -0,0 +1,112 @@
|
||||
/*! \file bitset.hpp
|
||||
\brief Support for types found in \<bitset\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_BITSET_HPP_
|
||||
#define CEREAL_TYPES_BITSET_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <bitset>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace bitset_detail
|
||||
{
|
||||
//! The type the bitset is encoded with
|
||||
/*! @internal */
|
||||
enum class type : uint8_t
|
||||
{
|
||||
ulong,
|
||||
ullong,
|
||||
string
|
||||
};
|
||||
}
|
||||
|
||||
//! Serializing (save) for std::bitset
|
||||
template <class Archive, size_t N> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::bitset<N> const & bits )
|
||||
{
|
||||
try
|
||||
{
|
||||
auto const b = bits.to_ulong();
|
||||
ar( CEREAL_NVP_("type", bitset_detail::type::ulong) );
|
||||
ar( CEREAL_NVP_("data", b) );
|
||||
}
|
||||
catch( std::overflow_error const & )
|
||||
{
|
||||
try
|
||||
{
|
||||
auto const b = bits.to_ullong();
|
||||
ar( CEREAL_NVP_("type", bitset_detail::type::ullong) );
|
||||
ar( CEREAL_NVP_("data", b) );
|
||||
}
|
||||
catch( std::overflow_error const & )
|
||||
{
|
||||
ar( CEREAL_NVP_("type", bitset_detail::type::string) );
|
||||
ar( CEREAL_NVP_("data", bits.to_string()) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Serializing (load) for std::bitset
|
||||
template <class Archive, size_t N> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::bitset<N> & bits )
|
||||
{
|
||||
bitset_detail::type t;
|
||||
ar( CEREAL_NVP_("type", t) );
|
||||
|
||||
switch( t )
|
||||
{
|
||||
case bitset_detail::type::ulong:
|
||||
{
|
||||
unsigned long b;
|
||||
ar( CEREAL_NVP_("data", b) );
|
||||
bits = std::bitset<N>( b );
|
||||
break;
|
||||
}
|
||||
case bitset_detail::type::ullong:
|
||||
{
|
||||
unsigned long long b;
|
||||
ar( CEREAL_NVP_("data", b) );
|
||||
bits = std::bitset<N>( b );
|
||||
break;
|
||||
}
|
||||
case bitset_detail::type::string:
|
||||
{
|
||||
std::string b;
|
||||
ar( CEREAL_NVP_("data", b) );
|
||||
bits = std::bitset<N>( b );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw Exception("Invalid bitset data representation");
|
||||
}
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_BITSET_HPP_
|
||||
106
libs/cereal/cereal/types/boost_variant.hpp
Normal file
106
libs/cereal/cereal/types/boost_variant.hpp
Normal file
@ -0,0 +1,106 @@
|
||||
/*! \file boost_variant.hpp
|
||||
\brief Support for boost::variant
|
||||
\ingroup OtherTypes */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_BOOST_VARIANT_HPP_
|
||||
#define CEREAL_TYPES_BOOST_VARIANT_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/mpl/size.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace variant_detail
|
||||
{
|
||||
//! @internal
|
||||
template <class Archive>
|
||||
struct variant_save_visitor : boost::static_visitor<>
|
||||
{
|
||||
variant_save_visitor(Archive & ar_) : ar(ar_) {}
|
||||
|
||||
template<class T>
|
||||
void operator()(T const & value) const
|
||||
{
|
||||
ar( CEREAL_NVP_("data", value) );
|
||||
}
|
||||
|
||||
Archive & ar;
|
||||
};
|
||||
|
||||
//! @internal
|
||||
template<int N, class Variant, class ... Args, class Archive>
|
||||
typename std::enable_if<N == boost::mpl::size<typename Variant::types>::value, void>::type
|
||||
load_variant(Archive & /*ar*/, int /*target*/, Variant & /*variant*/)
|
||||
{
|
||||
throw ::cereal::Exception("Error traversing variant during load");
|
||||
}
|
||||
|
||||
//! @internal
|
||||
template<int N, class Variant, class H, class ... T, class Archive>
|
||||
typename std::enable_if<N < boost::mpl::size<typename Variant::types>::value, void>::type
|
||||
load_variant(Archive & ar, int target, Variant & variant)
|
||||
{
|
||||
if(N == target)
|
||||
{
|
||||
H value;
|
||||
ar( CEREAL_NVP_("data", value) );
|
||||
variant = value;
|
||||
}
|
||||
else
|
||||
load_variant<N+1, Variant, T...>(ar, target, variant);
|
||||
}
|
||||
|
||||
} // namespace variant_detail
|
||||
|
||||
//! Saving for boost::variant
|
||||
template <class Archive, typename... VariantTypes> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> const & variant )
|
||||
{
|
||||
int32_t which = variant.which();
|
||||
ar( CEREAL_NVP_("which", which) );
|
||||
variant_detail::variant_save_visitor<Archive> visitor(ar);
|
||||
variant.apply_visitor(visitor);
|
||||
}
|
||||
|
||||
//! Loading for boost::variant
|
||||
template <class Archive, typename... VariantTypes> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> & variant )
|
||||
{
|
||||
typedef typename boost::variant<VariantTypes...>::types types;
|
||||
|
||||
int32_t which;
|
||||
ar( CEREAL_NVP_("which", which) );
|
||||
if(which >= boost::mpl::size<types>::value)
|
||||
throw Exception("Invalid 'which' selector when deserializing boost::variant");
|
||||
|
||||
variant_detail::load_variant<0, boost::variant<VariantTypes...>, VariantTypes...>(ar, which, variant);
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_BOOST_VARIANT_HPP_
|
||||
72
libs/cereal/cereal/types/chrono.hpp
Normal file
72
libs/cereal/cereal/types/chrono.hpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*! \file chrono.hpp
|
||||
\brief Support for types found in \<chrono\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_CHRONO_HPP_
|
||||
#define CEREAL_TYPES_CHRONO_HPP_
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving std::chrono::duration
|
||||
template <class Archive, class R, class P> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::chrono::duration<R, P> const & dur )
|
||||
{
|
||||
ar( CEREAL_NVP_("count", dur.count()) );
|
||||
}
|
||||
|
||||
//! Loading std::chrono::duration
|
||||
template <class Archive, class R, class P> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::chrono::duration<R, P> & dur )
|
||||
{
|
||||
R count;
|
||||
ar( CEREAL_NVP_("count", count) );
|
||||
|
||||
dur = std::chrono::duration<R, P>{count};
|
||||
}
|
||||
|
||||
//! Saving std::chrono::time_point
|
||||
template <class Archive, class C, class D> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::chrono::time_point<C, D> const & dur )
|
||||
{
|
||||
ar( CEREAL_NVP_("time_since_epoch", dur.time_since_epoch()) );
|
||||
}
|
||||
|
||||
//! Loading std::chrono::time_point
|
||||
template <class Archive, class C, class D> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::chrono::time_point<C, D> & dur )
|
||||
{
|
||||
D elapsed;
|
||||
ar( CEREAL_NVP_("time_since_epoch", elapsed) );
|
||||
|
||||
dur = std::chrono::time_point<C, D>{elapsed};
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_CHRONO_HPP_
|
||||
129
libs/cereal/cereal/types/common.hpp
Normal file
129
libs/cereal/cereal/types/common.hpp
Normal file
@ -0,0 +1,129 @@
|
||||
/*! \file common.hpp
|
||||
\brief Support common types - always included automatically
|
||||
\ingroup OtherTypes */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_COMMON_HPP_
|
||||
#define CEREAL_TYPES_COMMON_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace common_detail
|
||||
{
|
||||
//! Serialization for arrays if BinaryData is supported and we are arithmetic
|
||||
/*! @internal */
|
||||
template <class Archive, class T> inline
|
||||
void serializeArray( Archive & ar, T & array, std::true_type /* binary_supported */ )
|
||||
{
|
||||
ar( binary_data( array, sizeof(array) ) );
|
||||
}
|
||||
|
||||
//! Serialization for arrays if BinaryData is not supported or we are not arithmetic
|
||||
/*! @internal */
|
||||
template <class Archive, class T> inline
|
||||
void serializeArray( Archive & ar, T & array, std::false_type /* binary_supported */ )
|
||||
{
|
||||
for( auto & i : array )
|
||||
ar( i );
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
//! Gets the underlying type of an enum
|
||||
/*! @internal */
|
||||
template <class T, bool IsEnum>
|
||||
struct enum_underlying_type : std::false_type {};
|
||||
|
||||
//! Gets the underlying type of an enum
|
||||
/*! Specialization for when we actually have an enum
|
||||
@internal */
|
||||
template <class T>
|
||||
struct enum_underlying_type<T, true> { using type = typename std::underlying_type<T>::type; };
|
||||
} // anon namespace
|
||||
|
||||
//! Checks if a type is an enum
|
||||
/*! This is needed over simply calling std::is_enum because the type
|
||||
traits checking at compile time will attempt to call something like
|
||||
load_minimal with a special NoConvertRef struct that wraps up the true type.
|
||||
|
||||
This will strip away any of that and also expose the true underlying type.
|
||||
@internal */
|
||||
template <class T>
|
||||
class is_enum
|
||||
{
|
||||
private:
|
||||
using DecayedT = typename std::decay<T>::type;
|
||||
using StrippedT = typename ::cereal::traits::strip_minimal<DecayedT>::type;
|
||||
|
||||
public:
|
||||
static const bool value = std::is_enum<StrippedT>::value;
|
||||
using type = StrippedT;
|
||||
using base_type = typename enum_underlying_type<StrippedT, value>::type;
|
||||
};
|
||||
}
|
||||
|
||||
//! Saving for enum types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<common_detail::is_enum<T>::value,
|
||||
typename common_detail::is_enum<T>::base_type>::type
|
||||
CEREAL_SAVE_MINIMAL_FUNCTION_NAME( Archive const &, T const & t )
|
||||
{
|
||||
return static_cast<typename common_detail::is_enum<T>::base_type>(t);
|
||||
}
|
||||
|
||||
//! Loading for enum types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<common_detail::is_enum<T>::value, void>::type
|
||||
CEREAL_LOAD_MINIMAL_FUNCTION_NAME( Archive const &, T && t,
|
||||
typename common_detail::is_enum<T>::base_type const & value )
|
||||
{
|
||||
t = reinterpret_cast<typename common_detail::is_enum<T>::type const &>( value );
|
||||
}
|
||||
|
||||
//! Serialization for raw pointers
|
||||
/*! This exists only to throw a static_assert to let users know we don't support raw pointers. */
|
||||
template <class Archive, class T> inline
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive &, T * & )
|
||||
{
|
||||
static_assert(cereal::traits::detail::delay_static_assert<T>::value,
|
||||
"Cereal does not support serializing raw pointers - please use a smart pointer");
|
||||
}
|
||||
|
||||
//! Serialization for C style arrays
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_array<T>::value, void>::type
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME(Archive & ar, T & array)
|
||||
{
|
||||
common_detail::serializeArray( ar, array,
|
||||
std::integral_constant<bool, traits::is_output_serializable<BinaryData<T>, Archive>::value &&
|
||||
std::is_arithmetic<typename std::remove_all_extents<T>::type>::value>() );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_COMMON_HPP_
|
||||
56
libs/cereal/cereal/types/complex.hpp
Normal file
56
libs/cereal/cereal/types/complex.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*! \file complex.hpp
|
||||
\brief Support for types found in \<complex\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_COMPLEX_HPP_
|
||||
#define CEREAL_TYPES_COMPLEX_HPP_
|
||||
|
||||
#include <complex>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Serializing (save) for std::complex
|
||||
template <class Archive, class T> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::complex<T> const & comp )
|
||||
{
|
||||
ar( CEREAL_NVP_("real", comp.real()),
|
||||
CEREAL_NVP_("imag", comp.imag()) );
|
||||
}
|
||||
|
||||
//! Serializing (load) for std::complex
|
||||
template <class Archive, class T> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::complex<T> & bits )
|
||||
{
|
||||
T real, imag;
|
||||
ar( CEREAL_NVP_("real", real),
|
||||
CEREAL_NVP_("imag", imag) );
|
||||
bits = {real, imag};
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_COMPLEX_HPP_
|
||||
62
libs/cereal/cereal/types/deque.hpp
Normal file
62
libs/cereal/cereal/types/deque.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*! \file deque.hpp
|
||||
\brief Support for types found in \<deque\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_DEQUE_HPP_
|
||||
#define CEREAL_TYPES_DEQUE_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <deque>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving for std::deque
|
||||
template <class Archive, class T, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::deque<T, A> const & deque )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(deque.size()) ) );
|
||||
|
||||
for( auto const & i : deque )
|
||||
ar( i );
|
||||
}
|
||||
|
||||
//! Loading for std::deque
|
||||
template <class Archive, class T, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::deque<T, A> & deque )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
deque.resize( static_cast<size_t>( size ) );
|
||||
|
||||
for( auto & i : deque )
|
||||
ar( i );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_DEQUE_HPP_
|
||||
68
libs/cereal/cereal/types/forward_list.hpp
Normal file
68
libs/cereal/cereal/types/forward_list.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
/*! \file forward_list.hpp
|
||||
\brief Support for types found in \<forward_list\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_FORWARD_LIST_HPP_
|
||||
#define CEREAL_TYPES_FORWARD_LIST_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <forward_list>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving for std::forward_list all other types
|
||||
template <class Archive, class T, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::forward_list<T, A> const & forward_list )
|
||||
{
|
||||
// write the size - note that this is slow because we need to traverse
|
||||
// the entire list. there are ways we could avoid this but this was chosen
|
||||
// since it works in the most general fashion with any archive type
|
||||
size_type const size = std::distance( forward_list.begin(), forward_list.end() );
|
||||
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
// write the list
|
||||
for( const auto & i : forward_list )
|
||||
ar( i );
|
||||
}
|
||||
|
||||
//! Loading for std::forward_list all other types from
|
||||
template <class Archive, class T, class A>
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::forward_list<T, A> & forward_list )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
forward_list.resize( static_cast<size_t>( size ) );
|
||||
|
||||
for( auto & i : forward_list )
|
||||
ar( i );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_FORWARD_LIST_HPP_
|
||||
62
libs/cereal/cereal/types/list.hpp
Normal file
62
libs/cereal/cereal/types/list.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*! \file list.hpp
|
||||
\brief Support for types found in \<list\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_LIST_HPP_
|
||||
#define CEREAL_TYPES_LIST_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <list>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving for std::list
|
||||
template <class Archive, class T, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::list<T, A> const & list )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(list.size()) ) );
|
||||
|
||||
for( auto const & i : list )
|
||||
ar( i );
|
||||
}
|
||||
|
||||
//! Loading for std::list
|
||||
template <class Archive, class T, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::list<T, A> & list )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
list.resize( static_cast<size_t>( size ) );
|
||||
|
||||
for( auto & i : list )
|
||||
ar( i );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_LIST_HPP_
|
||||
108
libs/cereal/cereal/types/map.hpp
Normal file
108
libs/cereal/cereal/types/map.hpp
Normal file
@ -0,0 +1,108 @@
|
||||
/*! \file map.hpp
|
||||
\brief Support for types found in \<map\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_MAP_HPP_
|
||||
#define CEREAL_TYPES_MAP_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <map>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace map_detail
|
||||
{
|
||||
//! @internal
|
||||
template <class Archive, class MapT> inline
|
||||
void save( Archive & ar, MapT const & map )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(map.size()) ) );
|
||||
|
||||
for( const auto & i : map )
|
||||
{
|
||||
ar( make_map_item(i.first, i.second) );
|
||||
}
|
||||
}
|
||||
|
||||
//! @internal
|
||||
template <class Archive, class MapT> inline
|
||||
void load( Archive & ar, MapT & map )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
map.clear();
|
||||
|
||||
auto hint = map.begin();
|
||||
for( size_t i = 0; i < size; ++i )
|
||||
{
|
||||
typename MapT::key_type key;
|
||||
typename MapT::mapped_type value;
|
||||
|
||||
ar( make_map_item(key, value) );
|
||||
#ifdef CEREAL_OLDER_GCC
|
||||
hint = map.insert( hint, std::make_pair(std::move(key), std::move(value)) );
|
||||
#else // NOT CEREAL_OLDER_GCC
|
||||
hint = map.emplace_hint( hint, std::move( key ), std::move( value ) );
|
||||
#endif // NOT CEREAL_OLDER_GCC
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Saving for std::map
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::map<K, T, C, A> const & map )
|
||||
{
|
||||
map_detail::save( ar, map );
|
||||
}
|
||||
|
||||
//! Loading for std::map
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::map<K, T, C, A> & map )
|
||||
{
|
||||
map_detail::load( ar, map );
|
||||
}
|
||||
|
||||
//! Saving for std::multimap
|
||||
/*! @note serialization for this type is not guaranteed to preserve ordering */
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::multimap<K, T, C, A> const & multimap )
|
||||
{
|
||||
map_detail::save( ar, multimap );
|
||||
}
|
||||
|
||||
//! Loading for std::multimap
|
||||
/*! @note serialization for this type is not guaranteed to preserve ordering */
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::multimap<K, T, C, A> & multimap )
|
||||
{
|
||||
map_detail::load( ar, multimap );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_MAP_HPP_
|
||||
392
libs/cereal/cereal/types/memory.hpp
Normal file
392
libs/cereal/cereal/types/memory.hpp
Normal file
@ -0,0 +1,392 @@
|
||||
/*! \file memory.hpp
|
||||
\brief Support for types found in \<memory\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_SHARED_PTR_HPP_
|
||||
#define CEREAL_TYPES_SHARED_PTR_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace memory_detail
|
||||
{
|
||||
//! A wrapper class to notify cereal that it is ok to serialize the contained pointer
|
||||
/*! This mechanism allows us to intercept and properly handle polymorphic pointers
|
||||
@internal */
|
||||
template<class T>
|
||||
struct PtrWrapper
|
||||
{
|
||||
PtrWrapper(T && p) : ptr(std::forward<T>(p)) {}
|
||||
T & ptr;
|
||||
|
||||
PtrWrapper & operator=( PtrWrapper const & ) = delete;
|
||||
};
|
||||
|
||||
//! Make a PtrWrapper
|
||||
/*! @internal */
|
||||
template<class T> inline
|
||||
PtrWrapper<T> make_ptr_wrapper(T && t)
|
||||
{
|
||||
return {std::forward<T>(t)};
|
||||
}
|
||||
|
||||
//! A struct that acts as a wrapper around calling load_andor_construct
|
||||
/*! The purpose of this is to allow a load_and_construct call to properly enter into the
|
||||
'data' NVP of the ptr_wrapper
|
||||
@internal */
|
||||
template <class Archive, class T>
|
||||
struct LoadAndConstructLoadWrapper
|
||||
{
|
||||
LoadAndConstructLoadWrapper( T * ptr ) :
|
||||
construct( ptr )
|
||||
{ }
|
||||
|
||||
inline void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar )
|
||||
{
|
||||
::cereal::detail::Construct<T, Archive>::load_andor_construct( ar, construct );
|
||||
}
|
||||
|
||||
::cereal::construct<T> construct;
|
||||
};
|
||||
|
||||
//! A helper struct for saving and restoring the state of types that derive from
|
||||
//! std::enable_shared_from_this
|
||||
/*! This special struct is necessary because when a user uses load_and_construct,
|
||||
the weak_ptr (or whatever implementation defined variant) that allows
|
||||
enable_shared_from_this to function correctly will not be initialized properly.
|
||||
|
||||
This internal weak_ptr can also be modified by the shared_ptr that is created
|
||||
during the serialization of a polymorphic pointer, where cereal creates a
|
||||
wrapper shared_ptr out of a void pointer to the real data.
|
||||
|
||||
In the case of load_and_construct, this happens because it is the allocation
|
||||
of shared_ptr that perform this initialization, which we let happen on a buffer
|
||||
of memory (aligned_storage). This buffer is then used for placement new
|
||||
later on, effectively overwriting any initialized weak_ptr with a default
|
||||
initialized one, eventually leading to issues when the user calls shared_from_this.
|
||||
|
||||
To get around these issues, we will store the memory for the enable_shared_from_this
|
||||
portion of the class and replace it after whatever happens to modify it (e.g. the
|
||||
user performing construction or the wrapper shared_ptr in saving).
|
||||
|
||||
Example usage:
|
||||
|
||||
@code{.cpp}
|
||||
T * myActualPointer;
|
||||
{
|
||||
EnableSharedStateHelper<T> helper( myActualPointer ); // save the state
|
||||
std::shared_ptr<T> myPtr( myActualPointer ); // modifies the internal weak_ptr
|
||||
// helper restores state when it goes out of scope
|
||||
}
|
||||
@endcode
|
||||
|
||||
This is designed to be used in an RAII fashion - it will save state on construction
|
||||
and restore it on destruction.
|
||||
|
||||
@tparam T Type pointed to by shared_ptr
|
||||
@internal */
|
||||
template <class T>
|
||||
class EnableSharedStateHelper
|
||||
{
|
||||
// typedefs for parent type and storage type
|
||||
using BaseType = typename ::cereal::traits::get_shared_from_this_base<T>::type;
|
||||
using ParentType = std::enable_shared_from_this<BaseType>;
|
||||
using StorageType = typename std::aligned_storage<sizeof(ParentType)>::type;
|
||||
|
||||
public:
|
||||
//! Saves the state of some type inheriting from enable_shared_from_this
|
||||
/*! @param ptr The raw pointer held by the shared_ptr */
|
||||
inline EnableSharedStateHelper( T * ptr ) :
|
||||
itsPtr( static_cast<ParentType *>( ptr ) ),
|
||||
itsState()
|
||||
{
|
||||
std::memcpy( &itsState, itsPtr, sizeof(ParentType) );
|
||||
}
|
||||
|
||||
//! Restores the state of the held pointer
|
||||
inline ~EnableSharedStateHelper()
|
||||
{
|
||||
std::memcpy( itsPtr, &itsState, sizeof(ParentType) );
|
||||
}
|
||||
|
||||
private:
|
||||
ParentType * itsPtr;
|
||||
StorageType itsState;
|
||||
}; // end EnableSharedStateHelper
|
||||
|
||||
//! Performs loading and construction for a shared pointer that is derived from
|
||||
//! std::enable_shared_from_this
|
||||
/*! @param ar The archive
|
||||
@param ptr Raw pointer held by the shared_ptr
|
||||
@internal */
|
||||
template <class Archive, class T> inline
|
||||
void loadAndConstructSharedPtr( Archive & ar, T * ptr, std::true_type /* has_shared_from_this */ )
|
||||
{
|
||||
memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( ptr );
|
||||
memory_detail::EnableSharedStateHelper<T> state( ptr );
|
||||
|
||||
// let the user perform their initialization
|
||||
ar( CEREAL_NVP_("data", loadWrapper) );
|
||||
}
|
||||
|
||||
//! Performs loading and construction for a shared pointer that is NOT derived from
|
||||
//! std::enable_shared_from_this
|
||||
/*! This is the typical case, where we simply pass the load wrapper to the
|
||||
archive.
|
||||
|
||||
@param ar The archive
|
||||
@param ptr Raw pointer held by the shared_ptr
|
||||
@internal */
|
||||
template <class Archive, class T> inline
|
||||
void loadAndConstructSharedPtr( Archive & ar, T * ptr, std::false_type /* has_shared_from_this */ )
|
||||
{
|
||||
memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( ptr );
|
||||
ar( CEREAL_NVP_("data", loadWrapper) );
|
||||
}
|
||||
} // end namespace memory_detail
|
||||
|
||||
//! Saving std::shared_ptr for non polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
|
||||
{
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||
}
|
||||
|
||||
//! Loading std::shared_ptr, case when no user load and construct for non polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> & ptr )
|
||||
{
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||
}
|
||||
|
||||
//! Saving std::weak_ptr for non polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> const & ptr )
|
||||
{
|
||||
auto const sptr = ptr.lock();
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
|
||||
}
|
||||
|
||||
//! Loading std::weak_ptr for non polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> & ptr )
|
||||
{
|
||||
std::shared_ptr<T> sptr;
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
|
||||
ptr = sptr;
|
||||
}
|
||||
|
||||
//! Saving std::unique_ptr for non polymorphic types
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
|
||||
{
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||
}
|
||||
|
||||
//! Loading std::unique_ptr, case when user provides load_and_construct for non polymorphic types
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> & ptr )
|
||||
{
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
// Pointer wrapper implementations follow below
|
||||
|
||||
//! Saving std::shared_ptr (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> const &> const & wrapper )
|
||||
{
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
uint32_t id = ar.registerSharedPointer( ptr.get() );
|
||||
ar( CEREAL_NVP_("id", id) );
|
||||
|
||||
if( id & detail::msb_32bit )
|
||||
{
|
||||
ar( CEREAL_NVP_("data", *ptr) );
|
||||
}
|
||||
}
|
||||
|
||||
//! Loading std::shared_ptr, case when user load and construct (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<traits::has_load_and_construct<T, Archive>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
|
||||
{
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
uint32_t id;
|
||||
|
||||
ar( CEREAL_NVP_("id", id) );
|
||||
|
||||
if( id & detail::msb_32bit )
|
||||
{
|
||||
// Storage type for the pointer - since we can't default construct this type,
|
||||
// we'll allocate it using std::aligned_storage and use a custom deleter
|
||||
using ST = typename std::aligned_storage<sizeof(T)>::type;
|
||||
|
||||
// Valid flag - set to true once construction finishes
|
||||
// This prevents us from calling the destructor on
|
||||
// uninitialized data.
|
||||
auto valid = std::make_shared<bool>( false );
|
||||
|
||||
// Allocate our storage, which we will treat as
|
||||
// uninitialized until initialized with placement new
|
||||
ptr.reset( reinterpret_cast<T *>( new ST() ),
|
||||
[=]( T * t )
|
||||
{
|
||||
if( valid )
|
||||
t->~T();
|
||||
|
||||
delete reinterpret_cast<ST *>( t );
|
||||
} );
|
||||
|
||||
// Register the pointer
|
||||
ar.registerSharedPointer( id, ptr );
|
||||
|
||||
// Perform the actual loading and allocation
|
||||
memory_detail::loadAndConstructSharedPtr( ar, ptr.get(), typename ::cereal::traits::has_shared_from_this<T>::type() );
|
||||
|
||||
// Mark pointer as valid (initialized)
|
||||
*valid = true;
|
||||
}
|
||||
else
|
||||
ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
|
||||
}
|
||||
|
||||
//! Loading std::shared_ptr, case when no user load and construct (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!traits::has_load_and_construct<T, Archive>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
|
||||
{
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
uint32_t id;
|
||||
|
||||
ar( CEREAL_NVP_("id", id) );
|
||||
|
||||
if( id & detail::msb_32bit )
|
||||
{
|
||||
ptr.reset( detail::Construct<T, Archive>::load_andor_construct() );
|
||||
ar.registerSharedPointer( id, ptr );
|
||||
ar( CEREAL_NVP_("data", *ptr) );
|
||||
}
|
||||
else
|
||||
ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
|
||||
}
|
||||
|
||||
//! Saving std::unique_ptr (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T, class D> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> const &> const & wrapper )
|
||||
{
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
// unique_ptr get one byte of metadata which signifies whether they were a nullptr
|
||||
// 0 == nullptr
|
||||
// 1 == not null
|
||||
|
||||
if( !ptr )
|
||||
ar( CEREAL_NVP_("valid", uint8_t(0)) );
|
||||
else
|
||||
{
|
||||
ar( CEREAL_NVP_("valid", uint8_t(1)) );
|
||||
ar( CEREAL_NVP_("data", *ptr) );
|
||||
}
|
||||
}
|
||||
|
||||
//! Loading std::unique_ptr, case when user provides load_and_construct (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<traits::has_load_and_construct<T, Archive>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
|
||||
{
|
||||
uint8_t isValid;
|
||||
ar( CEREAL_NVP_("valid", isValid) );
|
||||
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
if( isValid )
|
||||
{
|
||||
// Storage type for the pointer - since we can't default construct this type,
|
||||
// we'll allocate it using std::aligned_storage
|
||||
using ST = typename std::aligned_storage<sizeof(T)>::type;
|
||||
|
||||
// Allocate storage - note the ST type so that deleter is correct if
|
||||
// an exception is thrown before we are initialized
|
||||
std::unique_ptr<ST> stPtr( new ST() );
|
||||
|
||||
// Use wrapper to enter into "data" nvp of ptr_wrapper
|
||||
memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( reinterpret_cast<T *>( stPtr.get() ) );
|
||||
|
||||
// Initialize storage
|
||||
ar( CEREAL_NVP_("data", loadWrapper) );
|
||||
|
||||
// Transfer ownership to correct unique_ptr type
|
||||
ptr.reset( reinterpret_cast<T *>( stPtr.release() ) );
|
||||
}
|
||||
else
|
||||
ptr.reset( nullptr );
|
||||
}
|
||||
|
||||
//! Loading std::unique_ptr, case when no load_and_construct (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<!traits::has_load_and_construct<T, Archive>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
|
||||
{
|
||||
uint8_t isValid;
|
||||
ar( CEREAL_NVP_("valid", isValid) );
|
||||
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
if( isValid )
|
||||
{
|
||||
ptr.reset( detail::Construct<T, Archive>::load_andor_construct() );
|
||||
ar( CEREAL_NVP_( "data", *ptr ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr.reset( nullptr );
|
||||
}
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_SHARED_PTR_HPP_
|
||||
462
libs/cereal/cereal/types/polymorphic.hpp
Normal file
462
libs/cereal/cereal/types/polymorphic.hpp
Normal file
@ -0,0 +1,462 @@
|
||||
/*! \file polymorphic.hpp
|
||||
\brief Support for pointers to polymorphic base classes
|
||||
\ingroup OtherTypes */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_POLYMORPHIC_HPP_
|
||||
#define CEREAL_TYPES_POLYMORPHIC_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/types/memory.hpp>
|
||||
|
||||
#include <cereal/details/util.hpp>
|
||||
#include <cereal/details/helpers.hpp>
|
||||
#include <cereal/details/traits.hpp>
|
||||
#include <cereal/details/polymorphic_impl.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STATIC_CONSTEXPR static
|
||||
#else
|
||||
#define STATIC_CONSTEXPR static constexpr
|
||||
#endif
|
||||
|
||||
//! Registers a derived polymorphic type with cereal
|
||||
/*! Polymorphic types must be registered before smart
|
||||
pointers to them can be serialized. Note that base
|
||||
classes do not need to be registered.
|
||||
|
||||
Registering a type lets cereal know how to properly
|
||||
serialize it when a smart pointer to a base object is
|
||||
used in conjunction with a derived class.
|
||||
|
||||
This assumes that all relevant archives have also
|
||||
previously been registered. Registration for archives
|
||||
is usually done in the header file in which they are
|
||||
defined. This means that type registration needs to
|
||||
happen after specific archives to be used are included.
|
||||
|
||||
It is recommended that type registration be done in
|
||||
the header file in which the type is declared.
|
||||
|
||||
Registration can also be placed in a source file,
|
||||
but this may require the use of the
|
||||
CEREAL_REGISTER_DYNAMIC_INIT macro (see below).
|
||||
|
||||
Registration may be called repeatedly for the same
|
||||
type in different translation units to add support
|
||||
for additional archives if they are not initially
|
||||
available (included and registered).
|
||||
|
||||
When building serialization support as a DLL on
|
||||
Windows, registration must happen in the header file.
|
||||
On Linux and Mac things should still work properly
|
||||
if placed in a source file, but see the above comments
|
||||
on registering in source files.
|
||||
|
||||
Polymorphic support in cereal requires RTTI to be
|
||||
enabled */
|
||||
#define CEREAL_REGISTER_TYPE(T) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
template <> \
|
||||
struct binding_name<T> \
|
||||
{ \
|
||||
STATIC_CONSTEXPR char const * name() { return #T; } \
|
||||
}; \
|
||||
} } /* end namespaces */ \
|
||||
CEREAL_BIND_TO_ARCHIVES(T)
|
||||
|
||||
//! Registers a polymorphic type with cereal, giving it a
|
||||
//! user defined name
|
||||
/*! In some cases the default name used with
|
||||
CEREAL_REGISTER_TYPE (the name of the type) may not be
|
||||
suitable. This macro allows any name to be associated
|
||||
with the type. The name should be unique */
|
||||
#define CEREAL_REGISTER_TYPE_WITH_NAME(T, Name) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
template <> \
|
||||
struct binding_name<T> \
|
||||
{ STATIC_CONSTEXPR char const * name() { return Name; } }; \
|
||||
} } /* end namespaces */ \
|
||||
CEREAL_BIND_TO_ARCHIVES(T)
|
||||
|
||||
//! Adds a way to force initialization of a translation unit containing
|
||||
//! calls to CEREAL_REGISTER_TYPE
|
||||
/*! In C++, dynamic initialization of non-local variables of a translation
|
||||
unit may be deferred until "the first odr-use of any function or variable
|
||||
defined in the same translation unit as the variable to be initialized."
|
||||
|
||||
Informally, odr-use means that your program takes the address of or binds
|
||||
a reference directly to an object, which must have a definition.
|
||||
|
||||
Since polymorphic type support in cereal relies on the dynamic
|
||||
initialization of certain global objects happening before
|
||||
serialization is performed, it is important to ensure that something
|
||||
from files that call CEREAL_REGISTER_TYPE is odr-used before serialization
|
||||
occurs, otherwise the registration will never take place. This may often
|
||||
be the case when serialization is built as a shared library external from
|
||||
your main program.
|
||||
|
||||
This macro, with any name of your choosing, should be placed into the
|
||||
source file that contains calls to CEREAL_REGISTER_TYPE.
|
||||
|
||||
Its counterpart, CEREAL_FORCE_DYNAMIC_INIT, should be placed in its
|
||||
associated header file such that it is included in the translation units
|
||||
(source files) in which you want the registration to appear.
|
||||
|
||||
@relates CEREAL_FORCE_DYNAMIC_INIT
|
||||
*/
|
||||
#define CEREAL_REGISTER_DYNAMIC_INIT(LibName) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
void CEREAL_DLL_EXPORT dynamic_init_dummy_##LibName() {} \
|
||||
} } /* end namespaces */
|
||||
|
||||
//! Forces dynamic initialization of polymorphic support in a
|
||||
//! previously registered source file
|
||||
/*! @sa CEREAL_REGISTER_DYNAMIC_INIT
|
||||
|
||||
See CEREAL_REGISTER_DYNAMIC_INIT for detailed explanation
|
||||
of how this macro should be used. The name used should
|
||||
match that for CEREAL_REGISTER_DYNAMIC_INIT. */
|
||||
#define CEREAL_FORCE_DYNAMIC_INIT(LibName) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
void dynamic_init_dummy_##LibName(); \
|
||||
} /* end detail */ \
|
||||
namespace { \
|
||||
void dynamic_init_##LibName() \
|
||||
{ \
|
||||
::cereal::detail::dynamic_init_dummy_##LibName(); \
|
||||
} \
|
||||
} } /* end namespaces */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#undef CONSTEXPR
|
||||
#endif
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace polymorphic_detail
|
||||
{
|
||||
//! Error message used for unregistered polymorphic types
|
||||
/*! @internal */
|
||||
#define UNREGISTERED_POLYMORPHIC_EXCEPTION(LoadSave, Name) \
|
||||
throw cereal::Exception("Trying to " #LoadSave " an unregistered polymorphic type (" + Name + ").\n" \
|
||||
"Make sure your type is registered with CEREAL_REGISTER_TYPE and that the archive " \
|
||||
"you are using was included (and registered with CEREAL_REGISTER_ARCHIVE) prior to calling CEREAL_REGISTER_TYPE.\n" \
|
||||
"If your type is already registered and you still see this error, you may need to use CEREAL_REGISTER_DYNAMIC_INIT.");
|
||||
|
||||
//! Get an input binding from the given archive by deserializing the type meta data
|
||||
/*! @internal */
|
||||
template<class Archive> inline
|
||||
typename ::cereal::detail::InputBindingMap<Archive>::Serializers getInputBinding(Archive & ar, std::uint32_t const nameid)
|
||||
{
|
||||
// If the nameid is zero, we serialized a null pointer
|
||||
if(nameid == 0)
|
||||
{
|
||||
typename ::cereal::detail::InputBindingMap<Archive>::Serializers emptySerializers;
|
||||
emptySerializers.shared_ptr = [](void*, std::shared_ptr<void> & ptr) { ptr.reset(); };
|
||||
emptySerializers.unique_ptr = [](void*, std::unique_ptr<void, ::cereal::detail::EmptyDeleter<void>> & ptr) { ptr.reset( nullptr ); };
|
||||
return emptySerializers;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
if(nameid & detail::msb_32bit)
|
||||
{
|
||||
ar( CEREAL_NVP_("polymorphic_name", name) );
|
||||
ar.registerPolymorphicName(nameid, name);
|
||||
}
|
||||
else
|
||||
name = ar.getPolymorphicName(nameid);
|
||||
|
||||
auto & bindingMap = detail::StaticObject<detail::InputBindingMap<Archive>>::getInstance().map;
|
||||
|
||||
auto binding = bindingMap.find(name);
|
||||
if(binding == bindingMap.end())
|
||||
UNREGISTERED_POLYMORPHIC_EXCEPTION(load, name)
|
||||
return binding->second;
|
||||
}
|
||||
|
||||
//! Serialize a shared_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
|
||||
/*! This check lets us try and skip doing polymorphic machinery if we can get away with
|
||||
using the derived class serialize function
|
||||
|
||||
Note that on MSVC 2013 preview, is_default_constructible<T> returns true for abstract classes with
|
||||
default constructors, but on clang/gcc this will return false. So we also need to check for that here.
|
||||
@internal */
|
||||
template<class Archive, class T> inline
|
||||
typename std::enable_if<(traits::is_default_constructible<T>::value
|
||||
|| traits::has_load_and_construct<T, Archive>::value)
|
||||
&& !std::is_abstract<T>::value, bool>::type
|
||||
serialize_wrapper(Archive & ar, std::shared_ptr<T> & ptr, std::uint32_t const nameid)
|
||||
{
|
||||
if(nameid & detail::msb2_32bit)
|
||||
{
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Serialize a unique_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
|
||||
/*! This check lets us try and skip doing polymorphic machinery if we can get away with
|
||||
using the derived class serialize function
|
||||
@internal */
|
||||
template<class Archive, class T, class D> inline
|
||||
typename std::enable_if<(traits::is_default_constructible<T>::value
|
||||
|| traits::has_load_and_construct<T, Archive>::value)
|
||||
&& !std::is_abstract<T>::value, bool>::type
|
||||
serialize_wrapper(Archive & ar, std::unique_ptr<T, D> & ptr, std::uint32_t const nameid)
|
||||
{
|
||||
if(nameid & detail::msb2_32bit)
|
||||
{
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Serialize a shared_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
|
||||
/*! This case is for when we can't actually construct the shared pointer. Normally this would be caught
|
||||
as the pointer itself is serialized, but since this is a polymorphic pointer, if we tried to serialize
|
||||
the pointer we'd end up back here recursively. So we have to catch the error here as well, if
|
||||
this was a polymorphic type serialized by its proper pointer type
|
||||
@internal */
|
||||
template<class Archive, class T> inline
|
||||
typename std::enable_if<(!traits::is_default_constructible<T>::value
|
||||
&& !traits::has_load_and_construct<T, Archive>::value)
|
||||
|| std::is_abstract<T>::value, bool>::type
|
||||
serialize_wrapper(Archive &, std::shared_ptr<T> &, std::uint32_t const nameid)
|
||||
{
|
||||
if(nameid & detail::msb2_32bit)
|
||||
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_construct function");
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Serialize a unique_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
|
||||
/*! This case is for when we can't actually construct the unique pointer. Normally this would be caught
|
||||
as the pointer itself is serialized, but since this is a polymorphic pointer, if we tried to serialize
|
||||
the pointer we'd end up back here recursively. So we have to catch the error here as well, if
|
||||
this was a polymorphic type serialized by its proper pointer type
|
||||
@internal */
|
||||
template<class Archive, class T, class D> inline
|
||||
typename std::enable_if<(!traits::is_default_constructible<T>::value
|
||||
&& !traits::has_load_and_construct<T, Archive>::value)
|
||||
|| std::is_abstract<T>::value, bool>::type
|
||||
serialize_wrapper(Archive &, std::unique_ptr<T, D> &, std::uint32_t const nameid)
|
||||
{
|
||||
if(nameid & detail::msb2_32bit)
|
||||
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_construct function");
|
||||
return false;
|
||||
}
|
||||
} // polymorphic_detail
|
||||
|
||||
// ######################################################################
|
||||
// Pointer serialization for polymorphic types
|
||||
|
||||
//! Saving std::shared_ptr for polymorphic types, abstract
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value && std::is_abstract<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
|
||||
{
|
||||
if(!ptr)
|
||||
{
|
||||
// same behavior as nullptr in memory implementation
|
||||
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
|
||||
return;
|
||||
}
|
||||
|
||||
std::type_info const & ptrinfo = typeid(*ptr.get());
|
||||
// ptrinfo can never be equal to T info since we can't have an instance
|
||||
// of an abstract object
|
||||
// this implies we need to do the lookup
|
||||
|
||||
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
|
||||
auto binding = bindingMap.find(std::type_index(ptrinfo));
|
||||
if(binding == bindingMap.end())
|
||||
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
|
||||
|
||||
binding->second.shared_ptr(&ar, ptr.get());
|
||||
}
|
||||
|
||||
//! Saving std::shared_ptr for polymorphic types, not abstract
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value && !std::is_abstract<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
|
||||
{
|
||||
if(!ptr)
|
||||
{
|
||||
// same behavior as nullptr in memory implementation
|
||||
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
|
||||
return;
|
||||
}
|
||||
|
||||
std::type_info const & ptrinfo = typeid(*ptr.get());
|
||||
static std::type_info const & tinfo = typeid(T);
|
||||
|
||||
if(ptrinfo == tinfo)
|
||||
{
|
||||
// The 2nd msb signals that the following pointer does not need to be
|
||||
// cast with our polymorphic machinery
|
||||
ar( CEREAL_NVP_("polymorphic_id", detail::msb2_32bit) );
|
||||
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
|
||||
auto binding = bindingMap.find(std::type_index(ptrinfo));
|
||||
if(binding == bindingMap.end())
|
||||
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
|
||||
|
||||
binding->second.shared_ptr(&ar, ptr.get());
|
||||
}
|
||||
|
||||
//! Loading std::shared_ptr for polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> & ptr )
|
||||
{
|
||||
std::uint32_t nameid;
|
||||
ar( CEREAL_NVP_("polymorphic_id", nameid) );
|
||||
|
||||
// Check to see if we can skip all of this polymorphism business
|
||||
if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
|
||||
return;
|
||||
|
||||
auto binding = polymorphic_detail::getInputBinding(ar, nameid);
|
||||
std::shared_ptr<void> result;
|
||||
binding.shared_ptr(&ar, result);
|
||||
ptr = std::static_pointer_cast<T>(result);
|
||||
}
|
||||
|
||||
//! Saving std::weak_ptr for polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> const & ptr )
|
||||
{
|
||||
auto const sptr = ptr.lock();
|
||||
ar( CEREAL_NVP_("locked_ptr", sptr) );
|
||||
}
|
||||
|
||||
//! Loading std::weak_ptr for polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> & ptr )
|
||||
{
|
||||
std::shared_ptr<T> sptr;
|
||||
ar( CEREAL_NVP_("locked_ptr", sptr) );
|
||||
ptr = sptr;
|
||||
}
|
||||
|
||||
//! Saving std::unique_ptr for polymorphic types that are abstract
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value && std::is_abstract<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
|
||||
{
|
||||
if(!ptr)
|
||||
{
|
||||
// same behavior as nullptr in memory implementation
|
||||
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
|
||||
return;
|
||||
}
|
||||
|
||||
std::type_info const & ptrinfo = typeid(*ptr.get());
|
||||
// ptrinfo can never be equal to T info since we can't have an instance
|
||||
// of an abstract object
|
||||
// this implies we need to do the lookup
|
||||
|
||||
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
|
||||
auto binding = bindingMap.find(std::type_index(ptrinfo));
|
||||
if(binding == bindingMap.end())
|
||||
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
|
||||
|
||||
binding->second.unique_ptr(&ar, ptr.get());
|
||||
}
|
||||
|
||||
//! Saving std::unique_ptr for polymorphic types, not abstract
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value && !std::is_abstract<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
|
||||
{
|
||||
if(!ptr)
|
||||
{
|
||||
// same behavior as nullptr in memory implementation
|
||||
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
|
||||
return;
|
||||
}
|
||||
|
||||
std::type_info const & ptrinfo = typeid(*ptr.get());
|
||||
static std::type_info const & tinfo = typeid(T);
|
||||
|
||||
if(ptrinfo == tinfo)
|
||||
{
|
||||
// The 2nd msb signals that the following pointer does not need to be
|
||||
// cast with our polymorphic machinery
|
||||
ar( CEREAL_NVP_("polymorphic_id", detail::msb2_32bit) );
|
||||
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
|
||||
auto binding = bindingMap.find(std::type_index(ptrinfo));
|
||||
if(binding == bindingMap.end())
|
||||
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
|
||||
|
||||
binding->second.unique_ptr(&ar, ptr.get());
|
||||
}
|
||||
|
||||
//! Loading std::unique_ptr, case when user provides load_and_construct for polymorphic types
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> & ptr )
|
||||
{
|
||||
std::uint32_t nameid;
|
||||
ar( CEREAL_NVP_("polymorphic_id", nameid) );
|
||||
|
||||
// Check to see if we can skip all of this polymorphism business
|
||||
if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
|
||||
return;
|
||||
|
||||
auto binding = polymorphic_detail::getInputBinding(ar, nameid);
|
||||
std::unique_ptr<void, ::cereal::detail::EmptyDeleter<void>> result;
|
||||
binding.unique_ptr(&ar, result);
|
||||
ptr.reset(static_cast<T*>(result.release()));
|
||||
}
|
||||
|
||||
#undef UNREGISTERED_POLYMORPHIC_EXCEPTION
|
||||
} // namespace cereal
|
||||
#endif // CEREAL_TYPES_POLYMORPHIC_HPP_
|
||||
130
libs/cereal/cereal/types/queue.hpp
Normal file
130
libs/cereal/cereal/types/queue.hpp
Normal file
@ -0,0 +1,130 @@
|
||||
/*! \file queue.hpp
|
||||
\brief Support for types found in \<queue\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_QUEUE_HPP_
|
||||
#define CEREAL_TYPES_QUEUE_HPP_
|
||||
|
||||
#include <cereal/details/helpers.hpp>
|
||||
#include <queue>
|
||||
|
||||
// The default container for queue is deque, so let's include that too
|
||||
#include <cereal/types/deque.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace queue_detail
|
||||
{
|
||||
//! Allows access to the protected container in queue
|
||||
/*! @internal */
|
||||
template <class T, class C> inline
|
||||
C const & container( std::queue<T, C> const & queue )
|
||||
{
|
||||
struct H : public std::queue<T, C>
|
||||
{
|
||||
static C const & get( std::queue<T, C> const & q )
|
||||
{
|
||||
return q.*(&H::c);
|
||||
}
|
||||
};
|
||||
|
||||
return H::get( queue );
|
||||
}
|
||||
|
||||
//! Allows access to the protected container in priority queue
|
||||
/*! @internal */
|
||||
template <class T, class C, class Comp> inline
|
||||
C const & container( std::priority_queue<T, C, Comp> const & priority_queue )
|
||||
{
|
||||
struct H : public std::priority_queue<T, C, Comp>
|
||||
{
|
||||
static C const & get( std::priority_queue<T, C, Comp> const & pq )
|
||||
{
|
||||
return pq.*(&H::c);
|
||||
}
|
||||
};
|
||||
|
||||
return H::get( priority_queue );
|
||||
}
|
||||
|
||||
//! Allows access to the protected comparator in priority queue
|
||||
/*! @internal */
|
||||
template <class T, class C, class Comp> inline
|
||||
Comp const & comparator( std::priority_queue<T, C, Comp> const & priority_queue )
|
||||
{
|
||||
struct H : public std::priority_queue<T, C, Comp>
|
||||
{
|
||||
static Comp const & get( std::priority_queue<T, C, Comp> const & pq )
|
||||
{
|
||||
return pq.*(&H::comp);
|
||||
}
|
||||
};
|
||||
|
||||
return H::get( priority_queue );
|
||||
}
|
||||
}
|
||||
|
||||
//! Saving for std::queue
|
||||
template <class Archive, class T, class C> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::queue<T, C> const & queue )
|
||||
{
|
||||
ar( CEREAL_NVP_("container", queue_detail::container( queue )) );
|
||||
}
|
||||
|
||||
//! Loading for std::queue
|
||||
template <class Archive, class T, class C> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::queue<T, C> & queue )
|
||||
{
|
||||
C container;
|
||||
ar( CEREAL_NVP_("container", container) );
|
||||
queue = std::queue<T, C>( std::move( container ) );
|
||||
}
|
||||
|
||||
//! Saving for std::priority_queue
|
||||
template <class Archive, class T, class C, class Comp> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::priority_queue<T, C, Comp> const & priority_queue )
|
||||
{
|
||||
ar( CEREAL_NVP_("comparator", queue_detail::comparator( priority_queue )) );
|
||||
ar( CEREAL_NVP_("container", queue_detail::container( priority_queue )) );
|
||||
}
|
||||
|
||||
//! Loading for std::priority_queue
|
||||
template <class Archive, class T, class C, class Comp> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::priority_queue<T, C, Comp> & priority_queue )
|
||||
{
|
||||
Comp comparator;
|
||||
ar( CEREAL_NVP_("comparator", comparator) );
|
||||
|
||||
C container;
|
||||
ar( CEREAL_NVP_("container", container) );
|
||||
|
||||
priority_queue = std::priority_queue<T, C, Comp>( comparator, std::move( container ) );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_QUEUE_HPP_
|
||||
103
libs/cereal/cereal/types/set.hpp
Normal file
103
libs/cereal/cereal/types/set.hpp
Normal file
@ -0,0 +1,103 @@
|
||||
/*! \file set.hpp
|
||||
\brief Support for types found in \<set\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_SET_HPP_
|
||||
#define CEREAL_TYPES_SET_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <set>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace set_detail
|
||||
{
|
||||
//! @internal
|
||||
template <class Archive, class SetT> inline
|
||||
void save( Archive & ar, SetT const & set )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(set.size()) ) );
|
||||
|
||||
for( const auto & i : set )
|
||||
ar( i );
|
||||
}
|
||||
|
||||
//! @internal
|
||||
template <class Archive, class SetT> inline
|
||||
void load( Archive & ar, SetT & set )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
set.clear();
|
||||
|
||||
auto hint = set.begin();
|
||||
for( size_type i = 0; i < size; ++i )
|
||||
{
|
||||
typename SetT::key_type key;
|
||||
|
||||
ar( key );
|
||||
#ifdef CEREAL_OLDER_GCC
|
||||
hint = set.insert( hint, std::move( key ) );
|
||||
#else // NOT CEREAL_OLDER_GCC
|
||||
hint = set.emplace_hint( hint, std::move( key ) );
|
||||
#endif // NOT CEREAL_OLDER_GCC
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Saving for std::set
|
||||
template <class Archive, class K, class C, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::set<K, C, A> const & set )
|
||||
{
|
||||
set_detail::save( ar, set );
|
||||
}
|
||||
|
||||
//! Loading for std::set
|
||||
template <class Archive, class K, class C, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::set<K, C, A> & set )
|
||||
{
|
||||
set_detail::load( ar, set );
|
||||
}
|
||||
|
||||
//! Saving for std::multiset
|
||||
template <class Archive, class K, class C, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::multiset<K, C, A> const & multiset )
|
||||
{
|
||||
set_detail::save( ar, multiset );
|
||||
}
|
||||
|
||||
//! Loading for std::multiset
|
||||
template <class Archive, class K, class C, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::multiset<K, C, A> & multiset )
|
||||
{
|
||||
set_detail::load( ar, multiset );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_SET_HPP_
|
||||
76
libs/cereal/cereal/types/stack.hpp
Normal file
76
libs/cereal/cereal/types/stack.hpp
Normal file
@ -0,0 +1,76 @@
|
||||
/*! \file stack.hpp
|
||||
\brief Support for types found in \<stack\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_STACK_HPP_
|
||||
#define CEREAL_TYPES_STACK_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <stack>
|
||||
|
||||
// The default container for stack is deque, so let's include that too
|
||||
#include <cereal/types/deque.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace stack_detail
|
||||
{
|
||||
//! Allows access to the protected container in stack
|
||||
template <class T, class C> inline
|
||||
C const & container( std::stack<T, C> const & stack )
|
||||
{
|
||||
struct H : public std::stack<T, C>
|
||||
{
|
||||
static C const & get( std::stack<T, C> const & s )
|
||||
{
|
||||
return s.*(&H::c);
|
||||
}
|
||||
};
|
||||
|
||||
return H::get( stack );
|
||||
}
|
||||
}
|
||||
|
||||
//! Saving for std::stack
|
||||
template <class Archive, class T, class C> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::stack<T, C> const & stack )
|
||||
{
|
||||
ar( CEREAL_NVP_("container", stack_detail::container( stack )) );
|
||||
}
|
||||
|
||||
//! Loading for std::stack
|
||||
template <class Archive, class T, class C> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::stack<T, C> & stack )
|
||||
{
|
||||
C container;
|
||||
ar( CEREAL_NVP_("container", container) );
|
||||
stack = std::stack<T, C>( std::move( container ) );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_STACK_HPP_
|
||||
61
libs/cereal/cereal/types/string.hpp
Normal file
61
libs/cereal/cereal/types/string.hpp
Normal file
@ -0,0 +1,61 @@
|
||||
/*! \file string.hpp
|
||||
\brief Support for types found in \<string\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_STRING_HPP_
|
||||
#define CEREAL_TYPES_STRING_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Serialization for basic_string types, if binary data is supported
|
||||
template<class Archive, class CharT, class Traits, class Alloc> inline
|
||||
typename std::enable_if<traits::is_output_serializable<BinaryData<CharT>, Archive>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME(Archive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
||||
{
|
||||
// Save number of chars + the data
|
||||
ar( make_size_tag( static_cast<size_type>(str.size()) ) );
|
||||
ar( binary_data( str.data(), str.size() * sizeof(CharT) ) );
|
||||
}
|
||||
|
||||
//! Serialization for basic_string types, if binary data is supported
|
||||
template<class Archive, class CharT, class Traits, class Alloc> inline
|
||||
typename std::enable_if<traits::is_input_serializable<BinaryData<CharT>, Archive>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME(Archive & ar, std::basic_string<CharT, Traits, Alloc> & str)
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
str.resize(static_cast<std::size_t>(size));
|
||||
ar( binary_data( const_cast<CharT *>( str.data() ), static_cast<std::size_t>(size) * sizeof(CharT) ) );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_STRING_HPP_
|
||||
|
||||
123
libs/cereal/cereal/types/tuple.hpp
Normal file
123
libs/cereal/cereal/types/tuple.hpp
Normal file
@ -0,0 +1,123 @@
|
||||
/*! \file tuple.hpp
|
||||
\brief Support for types found in \<tuple\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_TUPLE_HPP_
|
||||
#define CEREAL_TYPES_TUPLE_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <tuple>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace tuple_detail
|
||||
{
|
||||
//! Creates a c string from a sequence of characters
|
||||
/*! The c string created will alwas be prefixed by "tuple_element"
|
||||
Based on code from: http://stackoverflow/a/20973438/710791
|
||||
@internal */
|
||||
template<char...Cs>
|
||||
struct char_seq_to_c_str
|
||||
{
|
||||
static const int size = 14;// Size of array for the word: tuple_element
|
||||
typedef const char (&arr_type)[sizeof...(Cs) + size];
|
||||
static const char str[sizeof...(Cs) + size];
|
||||
};
|
||||
|
||||
// the word tuple_element plus a number
|
||||
//! @internal
|
||||
template<char...Cs>
|
||||
const char char_seq_to_c_str<Cs...>::str[sizeof...(Cs) + size] =
|
||||
{'t','u','p','l','e','_','e','l','e','m','e','n','t', Cs..., '\0'};
|
||||
|
||||
//! Converts a number into a sequence of characters
|
||||
/*! @tparam Q The quotient of dividing the original number by 10
|
||||
@tparam R The remainder of dividing the original number by 10
|
||||
@tparam C The sequence built so far
|
||||
@internal */
|
||||
template <size_t Q, size_t R, char ... C>
|
||||
struct to_string_impl
|
||||
{
|
||||
using type = typename to_string_impl<Q/10, Q%10, R+'0', C...>::type;
|
||||
};
|
||||
|
||||
//! Base case with no quotient
|
||||
/*! @internal */
|
||||
template <size_t R, char ... C>
|
||||
struct to_string_impl<0, R, C...>
|
||||
{
|
||||
using type = char_seq_to_c_str<R+'0', C...>;
|
||||
};
|
||||
|
||||
//! Generates a c string for a given index of a tuple
|
||||
/*! Example use:
|
||||
@code{cpp}
|
||||
tuple_element_name<3>::c_str();// returns "tuple_element3"
|
||||
@endcode
|
||||
@internal */
|
||||
template<size_t T>
|
||||
struct tuple_element_name
|
||||
{
|
||||
using type = typename to_string_impl<T/10, T%10>::type;
|
||||
static const typename type::arr_type c_str(){ return type::str; };
|
||||
};
|
||||
|
||||
// unwinds a tuple to save it
|
||||
//! @internal
|
||||
template <size_t Height>
|
||||
struct serialize
|
||||
{
|
||||
template <class Archive, class ... Types> inline
|
||||
static void apply( Archive & ar, std::tuple<Types...> & tuple )
|
||||
{
|
||||
serialize<Height - 1>::template apply( ar, tuple );
|
||||
ar( CEREAL_NVP_(tuple_element_name<Height - 1>::c_str(),
|
||||
std::get<Height - 1>( tuple )) );
|
||||
}
|
||||
};
|
||||
|
||||
// Zero height specialization - nothing to do here
|
||||
//! @internal
|
||||
template <>
|
||||
struct serialize<0>
|
||||
{
|
||||
template <class Archive, class ... Types> inline
|
||||
static void apply( Archive &, std::tuple<Types...> & )
|
||||
{ }
|
||||
};
|
||||
}
|
||||
|
||||
//! Serializing for std::tuple
|
||||
template <class Archive, class ... Types> inline
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, std::tuple<Types...> & tuple )
|
||||
{
|
||||
tuple_detail::serialize<std::tuple_size<std::tuple<Types...>>::value>::template apply( ar, tuple );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_TUPLE_HPP_
|
||||
100
libs/cereal/cereal/types/unordered_map.hpp
Normal file
100
libs/cereal/cereal/types/unordered_map.hpp
Normal file
@ -0,0 +1,100 @@
|
||||
/*! \file unordered_map.hpp
|
||||
\brief Support for types found in \<unordered_map\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_UNORDERED_MAP_HPP_
|
||||
#define CEREAL_TYPES_UNORDERED_MAP_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace unordered_map_detail
|
||||
{
|
||||
//! @internal
|
||||
template <class Archive, class MapT> inline
|
||||
void save( Archive & ar, MapT const & map )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(map.size()) ) );
|
||||
|
||||
for( const auto & i : map )
|
||||
ar( make_map_item(i.first, i.second) );
|
||||
}
|
||||
|
||||
//! @internal
|
||||
template <class Archive, class MapT> inline
|
||||
void load( Archive & ar, MapT & map )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
map.clear();
|
||||
map.reserve( static_cast<std::size_t>( size ) );
|
||||
|
||||
for( size_type i = 0; i < size; ++i )
|
||||
{
|
||||
typename MapT::key_type key;
|
||||
typename MapT::mapped_type value;
|
||||
|
||||
ar( make_map_item(key, value) );
|
||||
map.emplace( std::move( key ), std::move( value ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Saving for std::unordered_map
|
||||
template <class Archive, class K, class T, class H, class KE, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_map<K, T, H, KE, A> const & unordered_map )
|
||||
{
|
||||
unordered_map_detail::save( ar, unordered_map );
|
||||
}
|
||||
|
||||
//! Loading for std::unordered_map
|
||||
template <class Archive, class K, class T, class H, class KE, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_map<K, T, H, KE, A> & unordered_map )
|
||||
{
|
||||
unordered_map_detail::load( ar, unordered_map );
|
||||
}
|
||||
|
||||
//! Saving for std::unordered_multimap
|
||||
template <class Archive, class K, class T, class H, class KE, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_multimap<K, T, H, KE, A> const & unordered_multimap )
|
||||
{
|
||||
unordered_map_detail::save( ar, unordered_multimap );
|
||||
}
|
||||
|
||||
//! Loading for std::unordered_multimap
|
||||
template <class Archive, class K, class T, class H, class KE, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_multimap<K, T, H, KE, A> & unordered_multimap )
|
||||
{
|
||||
unordered_map_detail::load( ar, unordered_multimap );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_UNORDERED_MAP_HPP_
|
||||
99
libs/cereal/cereal/types/unordered_set.hpp
Normal file
99
libs/cereal/cereal/types/unordered_set.hpp
Normal file
@ -0,0 +1,99 @@
|
||||
/*! \file unordered_set.hpp
|
||||
\brief Support for types found in \<unordered_set\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_UNORDERED_SET_HPP_
|
||||
#define CEREAL_TYPES_UNORDERED_SET_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace unordered_set_detail
|
||||
{
|
||||
//! @internal
|
||||
template <class Archive, class SetT> inline
|
||||
void save( Archive & ar, SetT const & set )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(set.size()) ) );
|
||||
|
||||
for( const auto & i : set )
|
||||
ar( i );
|
||||
}
|
||||
|
||||
//! @internal
|
||||
template <class Archive, class SetT> inline
|
||||
void load( Archive & ar, SetT & set )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
set.clear();
|
||||
set.reserve( static_cast<std::size_t>( size ) );
|
||||
|
||||
for( size_type i = 0; i < size; ++i )
|
||||
{
|
||||
typename SetT::key_type key;
|
||||
|
||||
ar( key );
|
||||
set.emplace( std::move( key ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Saving for std::unordered_set
|
||||
template <class Archive, class K, class H, class KE, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_set<K, H, KE, A> const & unordered_set )
|
||||
{
|
||||
unordered_set_detail::save( ar, unordered_set );
|
||||
}
|
||||
|
||||
//! Loading for std::unordered_set
|
||||
template <class Archive, class K, class H, class KE, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_set<K, H, KE, A> & unordered_set )
|
||||
{
|
||||
unordered_set_detail::load( ar, unordered_set );
|
||||
}
|
||||
|
||||
//! Saving for std::unordered_multiset
|
||||
template <class Archive, class K, class H, class KE, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_multiset<K, H, KE, A> const & unordered_multiset )
|
||||
{
|
||||
unordered_set_detail::save( ar, unordered_multiset );
|
||||
}
|
||||
|
||||
//! Loading for std::unordered_multiset
|
||||
template <class Archive, class K, class H, class KE, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_multiset<K, H, KE, A> & unordered_multiset )
|
||||
{
|
||||
unordered_set_detail::load( ar, unordered_multiset );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_UNORDERED_SET_HPP_
|
||||
47
libs/cereal/cereal/types/utility.hpp
Normal file
47
libs/cereal/cereal/types/utility.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*! \file utility.hpp
|
||||
\brief Support for types found in \<utility\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_UTILITY_HPP_
|
||||
#define CEREAL_TYPES_UTILITY_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Serializing for std::pair
|
||||
template <class Archive, class T1, class T2> inline
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, std::pair<T1, T2> & pair )
|
||||
{
|
||||
ar( CEREAL_NVP_("first", pair.first),
|
||||
CEREAL_NVP_("second", pair.second) );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_UTILITY_HPP_
|
||||
89
libs/cereal/cereal/types/valarray.hpp
Normal file
89
libs/cereal/cereal/types/valarray.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
/*! \file valarray.hpp
|
||||
\brief Support for types found in \<valarray\>
|
||||
\ingroup STLSupport */
|
||||
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
|
||||
#ifndef CEREAL_TYPES_VALARRAY_HPP_
|
||||
#define CEREAL_TYPES_VALARRAY_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <valarray>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving for std::valarray arithmetic types, using binary serialization, if supported
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::valarray<T> const & valarray )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(valarray.size()) ) ); // number of elements
|
||||
ar( binary_data( &valarray[0], valarray.size() * sizeof(T) ) ); // &valarray[0] ok since guaranteed contiguous
|
||||
}
|
||||
|
||||
//! Loading for std::valarray arithmetic types, using binary serialization, if supported
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::valarray<T> & valarray )
|
||||
{
|
||||
size_type valarraySize;
|
||||
ar( make_size_tag( valarraySize ) );
|
||||
|
||||
valarray.resize( static_cast<std::size_t>( valarraySize ) );
|
||||
ar( binary_data( &valarray[0], static_cast<std::size_t>( valarraySize ) * sizeof(T) ) );
|
||||
}
|
||||
|
||||
//! Saving for std::valarray all other types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::valarray<T> const & valarray )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(valarray.size()) ) ); // number of elements
|
||||
for(auto && v : valarray)
|
||||
ar(v);
|
||||
}
|
||||
|
||||
//! Loading for std::valarray all other types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::valarray<T> & valarray )
|
||||
{
|
||||
size_type valarraySize;
|
||||
ar( make_size_tag( valarraySize ) );
|
||||
|
||||
valarray.resize( static_cast<size_t>( valarraySize ) );
|
||||
for(auto && v : valarray)
|
||||
ar(v);
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_VALARRAY_HPP_
|
||||
112
libs/cereal/cereal/types/vector.hpp
Normal file
112
libs/cereal/cereal/types/vector.hpp
Normal file
@ -0,0 +1,112 @@
|
||||
/*! \file vector.hpp
|
||||
\brief Support for types found in \<vector\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 RANDOLPH VOORHIES OR SHANE GRANT 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.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_VECTOR_HPP_
|
||||
#define CEREAL_TYPES_VECTOR_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Serialization for std::vectors of arithmetic (but not bool) using binary serialization, if supported
|
||||
template <class Archive, class T, class A> inline
|
||||
typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<T, A> const & vector )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
|
||||
ar( binary_data( vector.data(), vector.size() * sizeof(T) ) );
|
||||
}
|
||||
|
||||
//! Serialization for std::vectors of arithmetic (but not bool) using binary serialization, if supported
|
||||
template <class Archive, class T, class A> inline
|
||||
typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<T, A> & vector )
|
||||
{
|
||||
size_type vectorSize;
|
||||
ar( make_size_tag( vectorSize ) );
|
||||
|
||||
vector.resize( static_cast<std::size_t>( vectorSize ) );
|
||||
ar( binary_data( vector.data(), static_cast<std::size_t>( vectorSize ) * sizeof(T) ) );
|
||||
}
|
||||
|
||||
//! Serialization for non-arithmetic vector types
|
||||
template <class Archive, class T, class A> inline
|
||||
typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<T, A> const & vector )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
|
||||
for(auto && v : vector)
|
||||
ar( v );
|
||||
}
|
||||
|
||||
//! Serialization for non-arithmetic vector types
|
||||
template <class Archive, class T, class A> inline
|
||||
typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<T, A> & vector )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
vector.resize( static_cast<std::size_t>( size ) );
|
||||
for(auto && v : vector)
|
||||
ar( v );
|
||||
}
|
||||
|
||||
//! Serialization for bool vector types
|
||||
template <class Archive, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<bool, A> const & vector )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
|
||||
for(auto && v : vector)
|
||||
ar( static_cast<bool>(v) );
|
||||
}
|
||||
|
||||
//! Serialization for bool vector types
|
||||
template <class Archive, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<bool, A> & vector )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
vector.resize( static_cast<std::size_t>( size ) );
|
||||
for(auto && v : vector)
|
||||
{
|
||||
bool b;
|
||||
ar( b );
|
||||
v = b;
|
||||
}
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_VECTOR_HPP_
|
||||
33
libs/format/.travis.yml
Normal file
33
libs/format/.travis.yml
Normal file
@ -0,0 +1,33 @@
|
||||
language: cpp
|
||||
sudo: required # the doc target uses sudo to install dependencies
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: |-
|
||||
Gsnp9ERFnXt+diCfc7Vb72g+7HDn1MCHvw4zfUDdoBh9bxxFlLQRlzZZfwWhzni57lflrt
|
||||
0QHXafu+oBVOJuNv6WauV3+ZyuWIQRmNGjZFNLvZsXHK/dyad2vGQBPvEkb+8l/aCyTpbr
|
||||
6pxmyzLHSn1ZR7OX5rfPvwM3tOyZ3H0=
|
||||
matrix:
|
||||
- BUILD=Doc
|
||||
- BUILD=Debug STANDARD=0x
|
||||
- BUILD=Release STANDARD=98
|
||||
- BUILD=Release STANDARD=0x
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
env: BUILD=Doc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- kubuntu-backports # cmake 2.8.12
|
||||
packages:
|
||||
- cmake
|
||||
|
||||
script:
|
||||
- support/travis-build.py
|
||||
15
libs/format/Android.mk
Normal file
15
libs/format/Android.mk
Normal file
@ -0,0 +1,15 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := fmt_static
|
||||
LOCAL_MODULE_FILENAME := libfmt
|
||||
|
||||
LOCAL_SRC_FILES := fmt/format.cc
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
|
||||
|
||||
LOCAL_CFLAGS += -std=c++11 -fexceptions
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
105
libs/format/CMakeLists.txt
Normal file
105
libs/format/CMakeLists.txt
Normal file
@ -0,0 +1,105 @@
|
||||
message(STATUS "CMake version: ${CMAKE_VERSION}")
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
# Determine if fmt is built as a subproject (using add_subdirectory)
|
||||
# or if it is the master project.
|
||||
set(MASTER_PROJECT OFF)
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(MASTER_PROJECT ON)
|
||||
endif ()
|
||||
|
||||
# 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.")
|
||||
endif ()
|
||||
|
||||
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
|
||||
|
||||
# Options that control generation of various targets.
|
||||
option(FMT_DOC "Generate the doc target." ${MASTER_PROJECT})
|
||||
option(FMT_INSTALL "Generate the install target." ${MASTER_PROJECT})
|
||||
option(FMT_TEST "Generate the test target." ${MASTER_PROJECT})
|
||||
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}.")
|
||||
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})
|
||||
|
||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
|
||||
|
||||
include(cxx11)
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
||||
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wshadow -pedantic)
|
||||
endif ()
|
||||
|
||||
if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
# If Microsoft SDK is installed create script run-msbuild.bat that
|
||||
# calls SetEnv.cmd to set up build environment and runs msbuild.
|
||||
# It is useful when building Visual Studio projects with the SDK
|
||||
# toolchain rather than Visual Studio.
|
||||
include(FindSetEnv)
|
||||
if (WINSDK_SETENV)
|
||||
set(MSBUILD_SETUP "call \"${WINSDK_SETENV}\"")
|
||||
endif ()
|
||||
# Set FrameworkPathOverride to get rid of MSB3644 warnings.
|
||||
set(netfxpath "C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.0")
|
||||
file(WRITE run-msbuild.bat "
|
||||
${MSBUILD_SETUP}
|
||||
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
||||
endif ()
|
||||
|
||||
include(CheckSymbolExists)
|
||||
if (WIN32)
|
||||
check_symbol_exists(open io.h HAVE_OPEN)
|
||||
else ()
|
||||
check_symbol_exists(open fcntl.h HAVE_OPEN)
|
||||
endif ()
|
||||
|
||||
add_subdirectory(fmt)
|
||||
|
||||
if (FMT_DOC)
|
||||
add_subdirectory(doc)
|
||||
endif ()
|
||||
|
||||
if (FMT_TEST)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif ()
|
||||
|
||||
set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore)
|
||||
if (MASTER_PROJECT AND EXISTS ${gitignore})
|
||||
# Get the list of ignored files from .gitignore.
|
||||
file (STRINGS ${gitignore} lines)
|
||||
LIST(REMOVE_ITEM lines /doc/html)
|
||||
foreach (line ${lines})
|
||||
string(REPLACE "." "[.]" line "${line}")
|
||||
string(REPLACE "*" ".*" line "${line}")
|
||||
set(ignored_files ${ignored_files} "${line}$" "${line}/")
|
||||
endforeach ()
|
||||
set(ignored_files ${ignored_files}
|
||||
/.git /breathe /format-benchmark sphinx/ .buildinfo .doctrees)
|
||||
|
||||
set(CPACK_SOURCE_GENERATOR ZIP)
|
||||
set(CPACK_SOURCE_IGNORE_FILES ${ignored_files})
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME fmt-${FMT_VERSION})
|
||||
set(CPACK_PACKAGE_NAME fmt)
|
||||
set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.rst)
|
||||
include(CPack)
|
||||
endif ()
|
||||
900
libs/format/ChangeLog.rst
Normal file
900
libs/format/ChangeLog.rst
Normal file
@ -0,0 +1,900 @@
|
||||
3.0.0 - 2016-05-07
|
||||
------------------
|
||||
|
||||
* The project has been renamed from C++ Format (cppformat) to fmt for
|
||||
consistency with the used namespace and macro prefix
|
||||
(`#307 <https://github.com/fmtlib/fmt/issues/307>`_).
|
||||
Library headers are now located in the ``fmt`` directory:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
Including ``format.h`` from the ``cppformat`` directory is deprecated
|
||||
but works via a proxy header which will be removed in the next major version.
|
||||
|
||||
The documentation is now available at http://fmtlib.net.
|
||||
|
||||
* Added support for `strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like
|
||||
`date and time formatting <http://fmtlib.net/3.0.0/api.html#date-and-time-formatting>`_
|
||||
(`#283 <https://github.com/fmtlib/fmt/issues/283>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include "fmt/time.h"
|
||||
|
||||
std::time_t t = std::time(nullptr);
|
||||
// Prints "The date is 2016-04-29." (with the current date)
|
||||
fmt::print("The date is {:%Y-%m-%d}.", *std::localtime(&t));
|
||||
|
||||
* ``std::ostream`` support including formatting of user-defined types that provide
|
||||
overloaded ``operator<<`` has been moved to ``fmt/ostream.h``:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include "fmt/ostream.h"
|
||||
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
public:
|
||||
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_;
|
||||
}
|
||||
};
|
||||
|
||||
std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
|
||||
// s == "The date is 2012-12-9"
|
||||
|
||||
* Added support for `custom argument formatters
|
||||
<http://fmtlib.net/3.0.0/api.html#argument-formatters>`_
|
||||
(`#235 <https://github.com/fmtlib/fmt/issues/235>`_).
|
||||
|
||||
* Added support for locale-specific integer formatting with the ``n`` specifier
|
||||
(`#305 <https://github.com/fmtlib/fmt/issues/305>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
std::setlocale(LC_ALL, "en_US.utf8");
|
||||
fmt::print("cppformat: {:n}\n", 1234567); // prints 1,234,567
|
||||
|
||||
* Sign is now preserved when formatting an integer with an incorrect ``printf``
|
||||
format specifier (`#265 <https://github.com/fmtlib/fmt/issues/265>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::printf("%lld", -42); // prints -42
|
||||
|
||||
Note that it would be an undefined behavior in ``std::printf``.
|
||||
|
||||
* Length modifiers such as ``ll`` are now optional in printf formatting
|
||||
functions and the correct type is determined automatically
|
||||
(`#255 <https://github.com/fmtlib/fmt/issues/255>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::printf("%d", std::numeric_limits<long long>::max());
|
||||
|
||||
Note that it would be an undefined behavior in ``std::printf``.
|
||||
|
||||
* Added initial support for custom formatters
|
||||
(`#231 <https://github.com/fmtlib/fmt/issues/231>`_).
|
||||
|
||||
* Fixed detection of user-defined literal support on Intel C++ compiler
|
||||
(`#311 <https://github.com/fmtlib/fmt/issues/311>`_,
|
||||
`#312 <https://github.com/fmtlib/fmt/pull/312>`_).
|
||||
Thanks to `@dean0x7d (Dean Moldovan) <https://github.com/dean0x7d>`_ and
|
||||
`@speth (Ray Speth) <https://github.com/speth>`_.
|
||||
|
||||
* Reduced compile time
|
||||
(`#243 <https://github.com/fmtlib/fmt/pull/243>`_,
|
||||
`#249 <https://github.com/fmtlib/fmt/pull/249>`_,
|
||||
`#317 <https://github.com/fmtlib/fmt/issues/317>`_):
|
||||
|
||||
.. image:: https://cloud.githubusercontent.com/assets/4831417/11614060/
|
||||
b9e826d2-9c36-11e5-8666-d4131bf503ef.png
|
||||
|
||||
.. image:: https://cloud.githubusercontent.com/assets/4831417/11614080/
|
||||
6ac903cc-9c37-11e5-8165-26df6efae364.png
|
||||
|
||||
Thanks to `@dean0x7d (Dean Moldovan) <https://github.com/dean0x7d>`_.
|
||||
|
||||
* Compile test fixes (`#313 <https://github.com/fmtlib/fmt/pull/313>`_).
|
||||
Thanks to `@dean0x7d (Dean Moldovan) <https://github.com/dean0x7d>`_.
|
||||
|
||||
* Documentation fixes (`#239 <https://github.com/fmtlib/fmt/pull/239>`_,
|
||||
`#248 <https://github.com/fmtlib/fmt/issues/248>`_,
|
||||
`#252 <https://github.com/fmtlib/fmt/issues/252>`_,
|
||||
`#258 <https://github.com/fmtlib/fmt/pull/258>`_,
|
||||
`#260 <https://github.com/fmtlib/fmt/issues/260>`_,
|
||||
`#301 <https://github.com/fmtlib/fmt/issues/301>`_,
|
||||
`#309 <https://github.com/fmtlib/fmt/pull/309>`_).
|
||||
Thanks to `@ReadmeCritic <https://github.com/ReadmeCritic>`_
|
||||
`@Gachapen (Magnus Bjerke Vik) <https://github.com/Gachapen>`_ and
|
||||
`@jwilk (Jakub Wilk) <https://github.com/jwilk>`_.
|
||||
|
||||
* Fixed compiler and sanitizer warnings (
|
||||
`#244 <https://github.com/fmtlib/fmt/issues/244>`_,
|
||||
`#256 <https://github.com/fmtlib/fmt/pull/256>`_,
|
||||
`#259 <https://github.com/fmtlib/fmt/pull/259>`_,
|
||||
`#263 <https://github.com/fmtlib/fmt/issues/263>`_,
|
||||
`#274 <https://github.com/fmtlib/fmt/issues/274>`_,
|
||||
`#277 <https://github.com/fmtlib/fmt/pull/277>`_,
|
||||
`#286 <https://github.com/fmtlib/fmt/pull/286>`_,
|
||||
`#291 <https://github.com/fmtlib/fmt/issues/291>`_,
|
||||
`#296 <https://github.com/fmtlib/fmt/issues/296>`_,
|
||||
`#308 <https://github.com/fmtlib/fmt/issues/308>`_)
|
||||
Thanks to `@mwinterb <https://github.com/mwinterb>`_,
|
||||
`@pweiskircher (Patrik Weiskircher) <https://github.com/pweiskircher>`_,
|
||||
`@Naios <https://github.com/Naios>`_.
|
||||
|
||||
* Improved compatibility with Windows Store apps
|
||||
(`#280 <https://github.com/fmtlib/fmt/issues/280>`_,
|
||||
`#285 <https://github.com/fmtlib/fmt/pull/285>`_)
|
||||
Thanks to `@mwinterb <https://github.com/mwinterb>`_.
|
||||
|
||||
* Added tests of compatibility with older C++ standards
|
||||
(`#273 <https://github.com/fmtlib/fmt/pull/273>`_).
|
||||
Thanks to `@niosHD <https://github.com/niosHD>`_.
|
||||
|
||||
* Fixed Android build (`#271 <https://github.com/fmtlib/fmt/pull/271>`_).
|
||||
Thanks to `@newnon <https://github.com/newnon>`_.
|
||||
|
||||
* Changed ``ArgMap`` to be backed by a vector instead of a map.
|
||||
(`#261 <https://github.com/fmtlib/fmt/issues/261>`_,
|
||||
`#262 <https://github.com/fmtlib/fmt/pull/262>`_).
|
||||
Thanks to `@mwinterb <https://github.com/mwinterb>`_.
|
||||
|
||||
* Added ``fprintf`` overload that writes to a ``std::ostream``
|
||||
(`#251 <https://github.com/fmtlib/fmt/pull/251>`_).
|
||||
Thanks to `nickhutchinson (Nicholas Hutchinson) <https://github.com/nickhutchinson>`_.
|
||||
|
||||
* Export symbols when building a Windows DLL
|
||||
(`#245 <https://github.com/fmtlib/fmt/pull/245>`_).
|
||||
Thanks to `macdems (Maciek Dems) <https://github.com/macdems>`_.
|
||||
|
||||
* Fixed compilation on Cygwin (`#304 <https://github.com/fmtlib/fmt/issues/304>`_).
|
||||
|
||||
* Implemented a workaround for a bug in Apple LLVM version 4.2 of clang
|
||||
(`#276 <https://github.com/fmtlib/fmt/issues/276>`_).
|
||||
|
||||
* Implemented a workaround for Google Test bug
|
||||
`#705 <https://github.com/google/googletest/issues/705>`_ on gcc 6
|
||||
(`#268 <https://github.com/fmtlib/fmt/issues/268>`_).
|
||||
Thanks to `octoploid <https://github.com/octoploid>`_.
|
||||
|
||||
* Removed Biicode support because the latter has been discontinued.
|
||||
|
||||
2.1.1 - 2016-04-11
|
||||
------------------
|
||||
|
||||
* The install location for generated CMake files is now configurable via
|
||||
the ``FMT_CMAKE_DIR`` CMake variable
|
||||
(`#299 <https://github.com/fmtlib/fmt/pull/299>`_).
|
||||
Thanks to `@niosHD <https://github.com/niosHD>`_.
|
||||
|
||||
* Documentation fixes (`#252 <https://github.com/fmtlib/fmt/issues/252>`_).
|
||||
|
||||
2.1.0 - 2016-03-21
|
||||
------------------
|
||||
|
||||
* Project layout and build system improvements
|
||||
(`#267 <https://github.com/fmtlib/fmt/pull/267>`_):
|
||||
|
||||
* The code have been moved to the ``cppformat`` directory.
|
||||
Including ``format.h`` from the top-level directory is deprecated
|
||||
but works via a proxy header which will be removed in the next
|
||||
major version.
|
||||
|
||||
* C++ Format CMake targets now have proper interface definitions.
|
||||
|
||||
* Installed version of the library now supports the header-only
|
||||
configuration.
|
||||
|
||||
* Targets ``doc``, ``install``, and ``test`` are now disabled if C++ Format
|
||||
is included as a CMake subproject. They can be enabled by setting
|
||||
``FMT_DOC``, ``FMT_INSTALL``, and ``FMT_TEST`` in the parent project.
|
||||
|
||||
Thanks to `@niosHD <https://github.com/niosHD>`_.
|
||||
|
||||
2.0.1 - 2016-03-13
|
||||
------------------
|
||||
|
||||
* Improved CMake find and package support
|
||||
(`#264 <https://github.com/fmtlib/fmt/issues/264>`_).
|
||||
Thanks to `@niosHD <https://github.com/niosHD>`_.
|
||||
|
||||
* Fix compile error with Android NDK and mingw32
|
||||
(`#241 <https://github.com/fmtlib/fmt/issues/241>`_).
|
||||
Thanks to `@Gachapen (Magnus Bjerke Vik) <https://github.com/Gachapen>`_.
|
||||
|
||||
* Documentation fixes
|
||||
(`#248 <https://github.com/fmtlib/fmt/issues/248>`_,
|
||||
`#260 <https://github.com/fmtlib/fmt/issues/260>`_).
|
||||
|
||||
2.0.0 - 2015-12-01
|
||||
------------------
|
||||
|
||||
General
|
||||
~~~~~~~
|
||||
|
||||
* [Breaking] Named arguments
|
||||
(`#169 <https://github.com/fmtlib/fmt/pull/169>`_,
|
||||
`#173 <https://github.com/fmtlib/fmt/pull/173>`_,
|
||||
`#174 <https://github.com/fmtlib/fmt/pull/174>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::print("The answer is {answer}.", fmt::arg("answer", 42));
|
||||
|
||||
Thanks to `@jamboree <https://github.com/jamboree>`_.
|
||||
|
||||
* [Experimental] User-defined literals for format and named arguments
|
||||
(`#204 <https://github.com/fmtlib/fmt/pull/204>`_,
|
||||
`#206 <https://github.com/fmtlib/fmt/pull/206>`_,
|
||||
`#207 <https://github.com/fmtlib/fmt/pull/207>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
using namespace fmt::literals;
|
||||
fmt::print("The answer is {answer}.", "answer"_a=42);
|
||||
|
||||
Thanks to `@dean0x7d (Dean Moldovan) <https://github.com/dean0x7d>`_.
|
||||
|
||||
* [Breaking] Formatting of more than 16 arguments is now supported when using
|
||||
variadic templates
|
||||
(`#141 <https://github.com/fmtlib/fmt/issues/141>`_).
|
||||
Thanks to `@Shauren <https://github.com/Shauren>`_.
|
||||
|
||||
* Runtime width specification
|
||||
(`#168 <https://github.com/fmtlib/fmt/pull/168>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::format("{0:{1}}", 42, 5); // gives " 42"
|
||||
|
||||
Thanks to `@jamboree <https://github.com/jamboree>`_.
|
||||
|
||||
* [Breaking] Enums are now formatted with an overloaded ``std::ostream`` insertion
|
||||
operator (``operator<<``) if available
|
||||
(`#232 <https://github.com/fmtlib/fmt/issues/232>`_).
|
||||
|
||||
* [Breaking] Changed default ``bool`` format to textual, "true" or "false"
|
||||
(`#170 <https://github.com/fmtlib/fmt/issues/170>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::print("{}", true); // prints "true"
|
||||
|
||||
To print ``bool`` as a number use numeric format specifier such as ``d``:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::print("{:d}", true); // prints "1"
|
||||
|
||||
* ``fmt::printf`` and ``fmt::sprintf`` now support formatting of ``bool`` with the
|
||||
``%s`` specifier giving textual output, "true" or "false"
|
||||
(`#223 <https://github.com/fmtlib/fmt/pull/223>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::printf("%s", true); // prints "true"
|
||||
|
||||
Thanks to `@LarsGullik <https://github.com/LarsGullik>`_.
|
||||
|
||||
* [Breaking] ``signed char`` and ``unsigned char`` are now formatted as integers by default
|
||||
(`#217 <https://github.com/fmtlib/fmt/pull/217>`_).
|
||||
|
||||
* [Breaking] Pointers to C strings can now be formatted with the ``p`` specifier
|
||||
(`#223 <https://github.com/fmtlib/fmt/pull/223>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::print("{:p}", "test"); // prints pointer value
|
||||
|
||||
Thanks to `@LarsGullik <https://github.com/LarsGullik>`_.
|
||||
|
||||
* [Breaking] ``fmt::printf`` and ``fmt::sprintf`` now print null pointers as ``(nil)``
|
||||
and null strings as ``(null)`` for consistency with glibc
|
||||
(`#226 <https://github.com/fmtlib/fmt/pull/226>`_).
|
||||
Thanks to `@LarsGullik <https://github.com/LarsGullik>`_.
|
||||
|
||||
* [Breaking] ``fmt::(s)printf`` now supports formatting of objects of user-defined types
|
||||
that provide an overloaded ``std::ostream`` insertion operator (``operator<<``)
|
||||
(`#201 <https://github.com/fmtlib/fmt/issues/201>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::printf("The date is %s", Date(2012, 12, 9));
|
||||
|
||||
* [Breaking] The ``Buffer`` template is now part of the public API and can be used
|
||||
to implement custom memory buffers
|
||||
(`#140 <https://github.com/fmtlib/fmt/issues/140>`_).
|
||||
Thanks to `@polyvertex (Jean-Charles Lefebvre) <https://github.com/polyvertex>`_.
|
||||
|
||||
* [Breaking] Improved compatibility between ``BasicStringRef`` and
|
||||
`std::experimental::basic_string_view
|
||||
<http://en.cppreference.com/w/cpp/experimental/basic_string_view>`_
|
||||
(`#100 <https://github.com/fmtlib/fmt/issues/100>`_,
|
||||
`#159 <https://github.com/fmtlib/fmt/issues/159>`_,
|
||||
`#183 <https://github.com/fmtlib/fmt/issues/183>`_):
|
||||
|
||||
- Comparison operators now compare string content, not pointers
|
||||
- ``BasicStringRef::c_str`` replaced by ``BasicStringRef::data``
|
||||
- ``BasicStringRef`` is no longer assumed to be null-terminated
|
||||
|
||||
References to null-terminated strings are now represented by a new class,
|
||||
``BasicCStringRef``.
|
||||
|
||||
* Dependency on pthreads introduced by Google Test is now optional
|
||||
(`#185 <https://github.com/fmtlib/fmt/issues/185>`_).
|
||||
|
||||
* New CMake options ``FMT_DOC``, ``FMT_INSTALL`` and ``FMT_TEST`` to control
|
||||
generation of ``doc``, ``install`` and ``test`` targets respectively, on by default
|
||||
(`#197 <https://github.com/fmtlib/fmt/issues/197>`_,
|
||||
`#198 <https://github.com/fmtlib/fmt/issues/198>`_,
|
||||
`#200 <https://github.com/fmtlib/fmt/issues/200>`_).
|
||||
Thanks to `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_.
|
||||
|
||||
* ``noexcept`` is now used when compiling with MSVC2015
|
||||
(`#215 <https://github.com/fmtlib/fmt/pull/215>`_).
|
||||
Thanks to `@dmkrepo (Dmitriy) <https://github.com/dmkrepo>`_.
|
||||
|
||||
* Added an option to disable use of ``windows.h`` when ``FMT_USE_WINDOWS_H``
|
||||
is defined as 0 before including ``format.h``
|
||||
(`#171 <https://github.com/fmtlib/fmt/issues/171>`_).
|
||||
Thanks to `@alfps (Alf P. Steinbach) <https://github.com/alfps>`_.
|
||||
|
||||
* [Breaking] ``windows.h`` is now included with ``NOMINMAX`` unless
|
||||
``FMT_WIN_MINMAX`` is defined. This is done to prevent breaking code using
|
||||
``std::min`` and ``std::max`` and only affects the header-only configuration
|
||||
(`#152 <https://github.com/fmtlib/fmt/issues/152>`_,
|
||||
`#153 <https://github.com/fmtlib/fmt/pull/153>`_,
|
||||
`#154 <https://github.com/fmtlib/fmt/pull/154>`_).
|
||||
Thanks to `@DevO2012 <https://github.com/DevO2012>`_.
|
||||
|
||||
* Improved support for custom character types
|
||||
(`#171 <https://github.com/fmtlib/fmt/issues/171>`_).
|
||||
Thanks to `@alfps (Alf P. Steinbach) <https://github.com/alfps>`_.
|
||||
|
||||
* Added an option to disable use of IOStreams when ``FMT_USE_IOSTREAMS``
|
||||
is defined as 0 before including ``format.h``
|
||||
(`#205 <https://github.com/fmtlib/fmt/issues/205>`_,
|
||||
`#208 <https://github.com/fmtlib/fmt/pull/208>`_).
|
||||
Thanks to `@JodiTheTigger <https://github.com/JodiTheTigger>`_.
|
||||
|
||||
* Improved detection of ``isnan``, ``isinf`` and ``signbit``.
|
||||
|
||||
Optimization
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* Made formatting of user-defined types more efficient with a custom stream buffer
|
||||
(`#92 <https://github.com/fmtlib/fmt/issues/92>`_,
|
||||
`#230 <https://github.com/fmtlib/fmt/pull/230>`_).
|
||||
Thanks to `@NotImplemented <https://github.com/NotImplemented>`_.
|
||||
|
||||
* Further improved performance of ``fmt::Writer`` on integer formatting
|
||||
and fixed a minor regression. Now it is ~7% faster than ``karma::generate``
|
||||
on Karma's benchmark
|
||||
(`#186 <https://github.com/fmtlib/fmt/issues/186>`_).
|
||||
|
||||
* [Breaking] Reduced `compiled code size
|
||||
<https://github.com/fmtlib/fmt#compile-time-and-code-bloat>`_
|
||||
(`#143 <https://github.com/fmtlib/fmt/issues/143>`_,
|
||||
`#149 <https://github.com/fmtlib/fmt/pull/149>`_).
|
||||
|
||||
Distribution
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* [Breaking] Headers are now installed in
|
||||
``${CMAKE_INSTALL_PREFIX}/include/cppformat``
|
||||
(`#178 <https://github.com/fmtlib/fmt/issues/178>`_).
|
||||
Thanks to `@jackyf (Eugene V. Lyubimkin) <https://github.com/jackyf>`_.
|
||||
|
||||
* [Breaking] Changed the library name from ``format`` to ``cppformat``
|
||||
for consistency with the project name and to avoid potential conflicts
|
||||
(`#178 <https://github.com/fmtlib/fmt/issues/178>`_).
|
||||
Thanks to `@jackyf (Eugene V. Lyubimkin) <https://github.com/jackyf>`_.
|
||||
|
||||
* C++ Format is now available in `Debian <https://www.debian.org/>`_ GNU/Linux
|
||||
(`stretch <https://packages.debian.org/source/stretch/cppformat>`_,
|
||||
`sid <https://packages.debian.org/source/sid/cppformat>`_) and
|
||||
derived distributions such as
|
||||
`Ubuntu <https://launchpad.net/ubuntu/+source/cppformat>`_ 15.10 and later
|
||||
(`#155 <https://github.com/fmtlib/fmt/issues/155>`_)::
|
||||
|
||||
$ sudo apt-get install libcppformat1-dev
|
||||
|
||||
Thanks to `@jackyf (Eugene V. Lyubimkin) <https://github.com/jackyf>`_.
|
||||
|
||||
* `Packages for Fedora and RHEL <https://admin.fedoraproject.org/pkgdb/package/cppformat/>`_
|
||||
are now available. Thanks to Dave Johansen.
|
||||
|
||||
* C++ Format can now be installed via `Homebrew <http://brew.sh/>`_ on OS X
|
||||
(`#157 <https://github.com/fmtlib/fmt/issues/157>`_)::
|
||||
|
||||
$ brew install cppformat
|
||||
|
||||
Thanks to `@ortho <https://github.com/ortho>`_, Anatoliy Bulukin.
|
||||
|
||||
Documentation
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
* Migrated from ReadTheDocs to GitHub Pages for better responsiveness
|
||||
and reliability
|
||||
(`#128 <https://github.com/fmtlib/fmt/issues/128>`_).
|
||||
New documentation address is http://cppformat.github.io/.
|
||||
|
||||
|
||||
* Added `Building the documentation
|
||||
<http://fmtlib.net/2.0.0/usage.html#building-the-documentation>`_
|
||||
section to the documentation.
|
||||
|
||||
* Documentation build script is now compatible with Python 3 and newer pip versions.
|
||||
(`#189 <https://github.com/fmtlib/fmt/pull/189>`_,
|
||||
`#209 <https://github.com/fmtlib/fmt/issues/209>`_).
|
||||
Thanks to `@JodiTheTigger <https://github.com/JodiTheTigger>`_ and
|
||||
`@xentec <https://github.com/xentec>`_.
|
||||
|
||||
* Documentation fixes and improvements
|
||||
(`#36 <https://github.com/fmtlib/fmt/issues/36>`_,
|
||||
`#75 <https://github.com/fmtlib/fmt/issues/75>`_,
|
||||
`#125 <https://github.com/fmtlib/fmt/issues/125>`_,
|
||||
`#160 <https://github.com/fmtlib/fmt/pull/160>`_,
|
||||
`#161 <https://github.com/fmtlib/fmt/pull/161>`_,
|
||||
`#162 <https://github.com/fmtlib/fmt/issues/162>`_,
|
||||
`#165 <https://github.com/fmtlib/fmt/issues/165>`_,
|
||||
`#210 <https://github.com/fmtlib/fmt/issues/210>`_).
|
||||
Thanks to `@syohex (Syohei YOSHIDA) <https://github.com/syohex>`_ and
|
||||
bug reporters.
|
||||
|
||||
* Fixed out-of-tree documentation build
|
||||
(`#177 <https://github.com/fmtlib/fmt/issues/177>`_).
|
||||
Thanks to `@jackyf (Eugene V. Lyubimkin) <https://github.com/jackyf>`_.
|
||||
|
||||
Fixes
|
||||
~~~~~
|
||||
|
||||
* Fixed ``initializer_list`` detection
|
||||
(`#136 <https://github.com/fmtlib/fmt/issues/136>`_).
|
||||
Thanks to `@Gachapen (Magnus Bjerke Vik) <https://github.com/Gachapen>`_.
|
||||
|
||||
* [Breaking] Fixed formatting of enums with numeric format specifiers in
|
||||
``fmt::(s)printf``
|
||||
(`#131 <https://github.com/fmtlib/fmt/issues/131>`_,
|
||||
`#139 <https://github.com/fmtlib/fmt/issues/139>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
enum { ANSWER = 42 };
|
||||
fmt::printf("%d", ANSWER);
|
||||
|
||||
Thanks to `@Naios <https://github.com/Naios>`_.
|
||||
|
||||
* Improved compatibility with old versions of MinGW
|
||||
(`#129 <https://github.com/fmtlib/fmt/issues/129>`_,
|
||||
`#130 <https://github.com/fmtlib/fmt/pull/130>`_,
|
||||
`#132 <https://github.com/fmtlib/fmt/issues/132>`_).
|
||||
Thanks to `@cstamford (Christopher Stamford) <https://github.com/cstamford>`_.
|
||||
|
||||
* Fixed a compile error on MSVC with disabled exceptions
|
||||
(`#144 <https://github.com/fmtlib/fmt/issues/144>`_).
|
||||
|
||||
* Added a workaround for broken implementation of variadic templates in MSVC2012
|
||||
(`#148 <https://github.com/fmtlib/fmt/issues/148>`_).
|
||||
|
||||
* Placed the anonymous namespace within ``fmt`` namespace for the header-only
|
||||
configuration
|
||||
(`#171 <https://github.com/fmtlib/fmt/issues/171>`_).
|
||||
Thanks to `@alfps (Alf P. Steinbach) <https://github.com/alfps>`_.
|
||||
|
||||
* Fixed issues reported by Coverity Scan
|
||||
(`#187 <https://github.com/fmtlib/fmt/issues/187>`_,
|
||||
`#192 <https://github.com/fmtlib/fmt/issues/192>`_).
|
||||
|
||||
* Implemented a workaround for a name lookup bug in MSVC2010
|
||||
(`#188 <https://github.com/fmtlib/fmt/issues/188>`_).
|
||||
|
||||
* Fixed compiler warnings
|
||||
(`#95 <https://github.com/fmtlib/fmt/issues/95>`_,
|
||||
`#96 <https://github.com/fmtlib/fmt/issues/96>`_,
|
||||
`#114 <https://github.com/fmtlib/fmt/pull/114>`_,
|
||||
`#135 <https://github.com/fmtlib/fmt/issues/135>`_,
|
||||
`#142 <https://github.com/fmtlib/fmt/issues/142>`_,
|
||||
`#145 <https://github.com/fmtlib/fmt/issues/145>`_,
|
||||
`#146 <https://github.com/fmtlib/fmt/issues/146>`_,
|
||||
`#158 <https://github.com/fmtlib/fmt/issues/158>`_,
|
||||
`#163 <https://github.com/fmtlib/fmt/issues/163>`_,
|
||||
`#175 <https://github.com/fmtlib/fmt/issues/175>`_,
|
||||
`#190 <https://github.com/fmtlib/fmt/issues/190>`_,
|
||||
`#191 <https://github.com/fmtlib/fmt/pull/191>`_,
|
||||
`#194 <https://github.com/fmtlib/fmt/issues/194>`_,
|
||||
`#196 <https://github.com/fmtlib/fmt/pull/196>`_,
|
||||
`#216 <https://github.com/fmtlib/fmt/issues/216>`_,
|
||||
`#218 <https://github.com/fmtlib/fmt/pull/218>`_,
|
||||
`#220 <https://github.com/fmtlib/fmt/pull/220>`_,
|
||||
`#229 <https://github.com/fmtlib/fmt/pull/229>`_,
|
||||
`#233 <https://github.com/fmtlib/fmt/issues/233>`_,
|
||||
`#234 <https://github.com/fmtlib/fmt/issues/234>`_,
|
||||
`#236 <https://github.com/fmtlib/fmt/pull/236>`_,
|
||||
`#281 <https://github.com/fmtlib/fmt/issues/281>`_,
|
||||
`#289 <https://github.com/fmtlib/fmt/issues/289>`_).
|
||||
Thanks to `@seanmiddleditch (Sean Middleditch) <https://github.com/seanmiddleditch>`_,
|
||||
`@dixlorenz (Dix Lorenz) <https://github.com/dixlorenz>`_,
|
||||
`@CarterLi (李通洲) <https://github.com/CarterLi>`_,
|
||||
`@Naios <https://github.com/Naios>`_,
|
||||
`@fmatthew5876 (Matthew Fioravante) <https://github.com/fmatthew5876>`_,
|
||||
`@LevskiWeng (Levski Weng) <https://github.com/LevskiWeng>`_,
|
||||
`@rpopescu <https://github.com/rpopescu>`_,
|
||||
`@gabime (Gabi Melman) <https://github.com/gabime>`_,
|
||||
`@cubicool (Jeremy Moles) <https://github.com/cubicool>`_,
|
||||
`@jkflying (Julian Kent) <https://github.com/jkflying>`_,
|
||||
`@LogicalKnight (Sean L) <https://github.com/LogicalKnight>`_,
|
||||
`@inguin (Ingo van Lil) <https://github.com/inguin>`_ and
|
||||
`@Jopie64 (Johan) <https://github.com/Jopie64>`_.
|
||||
|
||||
* Fixed portability issues (mostly causing test failures) on ARM, ppc64, ppc64le,
|
||||
s390x and SunOS 5.11 i386 (
|
||||
`#138 <https://github.com/fmtlib/fmt/issues/138>`_,
|
||||
`#179 <https://github.com/fmtlib/fmt/issues/179>`_,
|
||||
`#180 <https://github.com/fmtlib/fmt/issues/180>`_,
|
||||
`#202 <https://github.com/fmtlib/fmt/issues/202>`_,
|
||||
`#225 <https://github.com/fmtlib/fmt/issues/225>`_,
|
||||
`Red Hat Bugzilla Bug 1260297 <https://bugzilla.redhat.com/show_bug.cgi?id=1260297>`_).
|
||||
Thanks to `@Naios <https://github.com/Naios>`_,
|
||||
`@jackyf (Eugene V. Lyubimkin) <https://github.com/jackyf>`_ and Dave Johansen.
|
||||
|
||||
* Fixed a name conflict with macro ``free`` defined in
|
||||
``crtdbg.h`` when ``_CRTDBG_MAP_ALLOC`` is set
|
||||
(`#211 <https://github.com/fmtlib/fmt/issues/211>`_).
|
||||
|
||||
* Fixed shared library build on OS X
|
||||
(`#212 <https://github.com/fmtlib/fmt/pull/212>`_).
|
||||
Thanks to `@dean0x7d (Dean Moldovan) <https://github.com/dean0x7d>`_.
|
||||
|
||||
* Fixed an overload conflict on MSVC when ``/Zc:wchar_t-`` option is specified
|
||||
(`#214 <https://github.com/fmtlib/fmt/pull/214>`_).
|
||||
Thanks to `@slavanap (Vyacheslav Napadovsky) <https://github.com/slavanap>`_.
|
||||
|
||||
* Improved compatibility with MSVC 2008
|
||||
(`#236 <https://github.com/fmtlib/fmt/pull/236>`_).
|
||||
Thanks to `@Jopie64 (Johan) <https://github.com/Jopie64>`_.
|
||||
|
||||
* Improved compatibility with bcc32
|
||||
(`#227 <https://github.com/fmtlib/fmt/issues/227>`_).
|
||||
|
||||
* Fixed ``static_assert`` detection on Clang
|
||||
(`#228 <https://github.com/fmtlib/fmt/pull/228>`_).
|
||||
Thanks to `@dean0x7d (Dean Moldovan) <https://github.com/dean0x7d>`_.
|
||||
|
||||
1.1.0 - 2015-03-06
|
||||
------------------
|
||||
|
||||
* Added ``BasicArrayWriter``, a class template that provides operations for
|
||||
formatting and writing data into a fixed-size array
|
||||
(`#105 <https://github.com/fmtlib/fmt/issues/105>`_ and
|
||||
`#122 <https://github.com/fmtlib/fmt/issues/122>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
char buffer[100];
|
||||
fmt::ArrayWriter w(buffer);
|
||||
w.write("The answer is {}", 42);
|
||||
|
||||
* Added `0 A.D. <http://play0ad.com/>`_ and `PenUltima Online (POL)
|
||||
<http://www.polserver.com/>`_ to the list of notable projects using C++ Format.
|
||||
|
||||
* C++ Format now uses MSVC intrinsics for better formatting performance
|
||||
(`#115 <https://github.com/fmtlib/fmt/pull/115>`_,
|
||||
`#116 <https://github.com/fmtlib/fmt/pull/116>`_,
|
||||
`#118 <https://github.com/fmtlib/fmt/pull/118>`_ and
|
||||
`#121 <https://github.com/fmtlib/fmt/pull/121>`_).
|
||||
Previously these optimizations where only used on GCC and Clang.
|
||||
Thanks to `@CarterLi <https://github.com/CarterLi>`_ and
|
||||
`@objectx <https://github.com/objectx>`_.
|
||||
|
||||
* CMake install target (`#119 <https://github.com/fmtlib/fmt/pull/119>`_).
|
||||
Thanks to `@TrentHouliston <https://github.com/TrentHouliston>`_.
|
||||
|
||||
You can now install C++ Format with ``make install`` command.
|
||||
|
||||
* Improved `Biicode <http://www.biicode.com/>`_ support
|
||||
(`#98 <https://github.com/fmtlib/fmt/pull/98>`_ and
|
||||
`#104 <https://github.com/fmtlib/fmt/pull/104>`_). Thanks to
|
||||
`@MariadeAnton <https://github.com/MariadeAnton>`_ and
|
||||
`@franramirez688 <https://github.com/franramirez688>`_.
|
||||
|
||||
* Improved support for building with `Android NDK
|
||||
<https://developer.android.com/tools/sdk/ndk/index.html>`_
|
||||
(`#107 <https://github.com/fmtlib/fmt/pull/107>`_).
|
||||
Thanks to `@newnon <https://github.com/newnon>`_.
|
||||
|
||||
The `android-ndk-example <https://github.com/fmtlib/android-ndk-example>`_
|
||||
repository provides and example of using C++ Format with Android NDK:
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/fmtlib/android-ndk-example/
|
||||
master/screenshot.png
|
||||
|
||||
* Improved documentation of ``SystemError`` and ``WindowsError``
|
||||
(`#54 <https://github.com/fmtlib/fmt/issues/54>`_).
|
||||
|
||||
* Various code improvements
|
||||
(`#110 <https://github.com/fmtlib/fmt/pull/110>`_,
|
||||
`#111 <https://github.com/fmtlib/fmt/pull/111>`_
|
||||
`#112 <https://github.com/fmtlib/fmt/pull/112>`_).
|
||||
Thanks to `@CarterLi <https://github.com/CarterLi>`_.
|
||||
|
||||
* Improved compile-time errors when formatting wide into narrow strings
|
||||
(`#117 <https://github.com/fmtlib/fmt/issues/117>`_).
|
||||
|
||||
* Fixed ``BasicWriter::write`` without formatting arguments when C++11 support
|
||||
is disabled (`#109 <https://github.com/fmtlib/fmt/issues/109>`_).
|
||||
|
||||
* Fixed header-only build on OS X with GCC 4.9
|
||||
(`#124 <https://github.com/fmtlib/fmt/issues/124>`_).
|
||||
|
||||
* Fixed packaging issues (`#94 <https://github.com/fmtlib/fmt/issues/94>`_).
|
||||
|
||||
* Added `changelog <https://github.com/fmtlib/fmt/blob/master/ChangeLog.rst>`_
|
||||
(`#103 <https://github.com/fmtlib/fmt/issues/103>`_).
|
||||
|
||||
1.0.0 - 2015-02-05
|
||||
------------------
|
||||
|
||||
* Add support for a header-only configuration when ``FMT_HEADER_ONLY`` is
|
||||
defined before including ``format.h``:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#define FMT_HEADER_ONLY
|
||||
#include "format.h"
|
||||
|
||||
* Compute string length in the constructor of ``BasicStringRef``
|
||||
instead of the ``size`` method
|
||||
(`#79 <https://github.com/fmtlib/fmt/issues/79>`_).
|
||||
This eliminates size computation for string literals on reasonable optimizing
|
||||
compilers.
|
||||
|
||||
* Fix formatting of types with overloaded ``operator <<`` for ``std::wostream``
|
||||
(`#86 <https://github.com/fmtlib/fmt/issues/86>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::format(L"The date is {0}", Date(2012, 12, 9));
|
||||
|
||||
* Fix linkage of tests on Arch Linux
|
||||
(`#89 <https://github.com/fmtlib/fmt/issues/89>`_).
|
||||
|
||||
* Allow precision specifier for non-float arguments
|
||||
(`#90 <https://github.com/fmtlib/fmt/issues/90>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::print("{:.3}\n", "Carpet"); // prints "Car"
|
||||
|
||||
* Fix build on Android NDK
|
||||
(`#93 <https://github.com/fmtlib/fmt/issues/93>`_)
|
||||
|
||||
* Improvements to documentation build procedure.
|
||||
|
||||
* Remove ``FMT_SHARED`` CMake variable in favor of standard `BUILD_SHARED_LIBS
|
||||
<http://www.cmake.org/cmake/help/v3.0/variable/BUILD_SHARED_LIBS.html>`_.
|
||||
|
||||
* Fix error handling in ``fmt::fprintf``.
|
||||
|
||||
* Fix a number of warnings.
|
||||
|
||||
0.12.0 - 2014-10-25
|
||||
-------------------
|
||||
|
||||
* [Breaking] Improved separation between formatting and buffer management.
|
||||
``Writer`` is now a base class that cannot be instantiated directly.
|
||||
The new ``MemoryWriter`` class implements the default buffer management
|
||||
with small allocations done on stack. So ``fmt::Writer`` should be replaced
|
||||
with ``fmt::MemoryWriter`` in variable declarations.
|
||||
|
||||
Old code:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::Writer w;
|
||||
|
||||
New code:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::MemoryWriter w;
|
||||
|
||||
If you pass ``fmt::Writer`` by reference, you can continue to do so:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
void f(fmt::Writer &w);
|
||||
|
||||
This doesn't affect the formatting API.
|
||||
|
||||
* Support for custom memory allocators
|
||||
(`#69 <https://github.com/fmtlib/fmt/issues/69>`_)
|
||||
|
||||
* Formatting functions now accept `signed char` and `unsigned char` strings as
|
||||
arguments (`#73 <https://github.com/fmtlib/fmt/issues/73>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
auto s = format("GLSL version: {}", glGetString(GL_VERSION));
|
||||
|
||||
* Reduced code bloat. According to the new `benchmark results
|
||||
<https://github.com/fmtlib/fmt#compile-time-and-code-bloat>`_,
|
||||
cppformat is close to ``printf`` and by the order of magnitude better than
|
||||
Boost Format in terms of compiled code size.
|
||||
|
||||
* Improved appearance of the documentation on mobile by using the `Sphinx
|
||||
Bootstrap theme <http://ryan-roemer.github.io/sphinx-bootstrap-theme/>`_:
|
||||
|
||||
.. |old| image:: https://cloud.githubusercontent.com/assets/576385/4792130/
|
||||
cd256436-5de3-11e4-9a62-c077d0c2b003.png
|
||||
|
||||
.. |new| image:: https://cloud.githubusercontent.com/assets/576385/4792131/
|
||||
cd29896c-5de3-11e4-8f59-cac952942bf0.png
|
||||
|
||||
+-------+-------+
|
||||
| Old | New |
|
||||
+-------+-------+
|
||||
| |old| | |new| |
|
||||
+-------+-------+
|
||||
|
||||
0.11.0 - 2014-08-21
|
||||
-------------------
|
||||
|
||||
* Safe printf implementation with a POSIX extension for positional arguments:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
||||
fmt::printf("%1$s, %3$d %2$s", weekday, month, day);
|
||||
|
||||
* Arguments of ``char`` type can now be formatted as integers
|
||||
(Issue `#55 <https://github.com/fmtlib/fmt/issues/55>`_):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::format("0x{0:02X}", 'a');
|
||||
|
||||
* Deprecated parts of the API removed.
|
||||
|
||||
* The library is now built and tested on MinGW with Appveyor in addition to
|
||||
existing test platforms Linux/GCC, OS X/Clang, Windows/MSVC.
|
||||
|
||||
0.10.0 - 2014-07-01
|
||||
-------------------
|
||||
|
||||
**Improved API**
|
||||
|
||||
* All formatting methods are now implemented as variadic functions instead
|
||||
of using ``operator<<`` for feeding arbitrary arguments into a temporary
|
||||
formatter object. This works both with C++11 where variadic templates are
|
||||
used and with older standards where variadic functions are emulated by
|
||||
providing lightweight wrapper functions defined with the ``FMT_VARIADIC``
|
||||
macro. You can use this macro for defining your own portable variadic
|
||||
functions:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
void report_error(const char *format, const fmt::ArgList &args) {
|
||||
fmt::print("Error: {}");
|
||||
fmt::print(format, args);
|
||||
}
|
||||
FMT_VARIADIC(void, report_error, const char *)
|
||||
|
||||
report_error("file not found: {}", path);
|
||||
|
||||
Apart from a more natural syntax, this also improves performance as there
|
||||
is no need to construct temporary formatter objects and control arguments'
|
||||
lifetimes. Because the wrapper functions are very lightweight, this doesn't
|
||||
cause code bloat even in pre-C++11 mode.
|
||||
|
||||
* Simplified common case of formatting an ``std::string``. Now it requires a
|
||||
single function call:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
std::string s = format("The answer is {}.", 42);
|
||||
|
||||
Previously it required 2 function calls:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
std::string s = str(Format("The answer is {}.") << 42);
|
||||
|
||||
Instead of unsafe ``c_str`` function, ``fmt::Writer`` should be used directly
|
||||
to bypass creation of ``std::string``:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::Writer w;
|
||||
w.write("The answer is {}.", 42);
|
||||
w.c_str(); // returns a C string
|
||||
|
||||
This doesn't do dynamic memory allocation for small strings and is less error
|
||||
prone as the lifetime of the string is the same as for ``std::string::c_str``
|
||||
which is well understood (hopefully).
|
||||
|
||||
* Improved consistency in naming functions that are a part of the public API.
|
||||
Now all public functions are lowercase following the standard library
|
||||
conventions. Previously it was a combination of lowercase and
|
||||
CapitalizedWords.
|
||||
Issue `#50 <https://github.com/fmtlib/fmt/issues/50>`_.
|
||||
|
||||
* Old functions are marked as deprecated and will be removed in the next
|
||||
release.
|
||||
|
||||
**Other Changes**
|
||||
|
||||
* Experimental support for printf format specifications (work in progress):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::printf("The answer is %d.", 42);
|
||||
std::string s = fmt::sprintf("Look, a %s!", "string");
|
||||
|
||||
* Support for hexadecimal floating point format specifiers ``a`` and ``A``:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
print("{:a}", -42.0); // Prints -0x1.5p+5
|
||||
print("{:A}", -42.0); // Prints -0X1.5P+5
|
||||
|
||||
* CMake option ``FMT_SHARED`` that specifies whether to build format as a
|
||||
shared library (off by default).
|
||||
|
||||
0.9.0 - 2014-05-13
|
||||
------------------
|
||||
|
||||
* More efficient implementation of variadic formatting functions.
|
||||
|
||||
* ``Writer::Format`` now has a variadic overload:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
Writer out;
|
||||
out.Format("Look, I'm {}!", "variadic");
|
||||
|
||||
* For efficiency and consistency with other overloads, variadic overload of
|
||||
the ``Format`` function now returns ``Writer`` instead of ``std::string``.
|
||||
Use the ``str`` function to convert it to ``std::string``:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
std::string s = str(Format("Look, I'm {}!", "variadic"));
|
||||
|
||||
* Replaced formatter actions with output sinks: ``NoAction`` -> ``NullSink``,
|
||||
``Write`` -> ``FileSink``, ``ColorWriter`` -> ``ANSITerminalSink``.
|
||||
This improves naming consistency and shouldn't affect client code unless
|
||||
these classes are used directly which should be rarely needed.
|
||||
|
||||
* Added ``ThrowSystemError`` function that formats a message and throws
|
||||
``SystemError`` containing the formatted message and system-specific error
|
||||
description. For example, the following code
|
||||
|
||||
.. code:: c++
|
||||
|
||||
FILE *f = fopen(filename, "r");
|
||||
if (!f)
|
||||
ThrowSystemError(errno, "Failed to open file '{}'") << filename;
|
||||
|
||||
will throw ``SystemError`` exception with description
|
||||
"Failed to open file '<filename>': No such file or directory" if file
|
||||
doesn't exist.
|
||||
|
||||
* Support for AppVeyor continuous integration platform.
|
||||
|
||||
* ``Format`` now throws ``SystemError`` in case of I/O errors.
|
||||
|
||||
* Improve test infrastructure. Print functions are now tested by redirecting
|
||||
the output to a pipe.
|
||||
|
||||
0.8.0 - 2014-04-14
|
||||
------------------
|
||||
|
||||
* Initial release
|
||||
23
libs/format/LICENSE.rst
Normal file
23
libs/format/LICENSE.rst
Normal file
@ -0,0 +1,23 @@
|
||||
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.
|
||||
411
libs/format/README.rst
Normal file
411
libs/format/README.rst
Normal file
@ -0,0 +1,411 @@
|
||||
{fmt}
|
||||
=====
|
||||
|
||||
.. image:: https://travis-ci.org/fmtlib/fmt.png?branch=master
|
||||
:target: https://travis-ci.org/fmtlib/fmt
|
||||
|
||||
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v
|
||||
:target: https://ci.appveyor.com/project/vitaut/fmt
|
||||
|
||||
.. image:: https://badges.gitter.im/Join%20Chat.svg
|
||||
:alt: Join the chat at https://gitter.im/fmtlib/fmt
|
||||
:target: https://gitter.im/fmtlib/fmt
|
||||
|
||||
**fmt** is an open-source formatting library for C++.
|
||||
It can be used as a safe alternative to printf or as a fast
|
||||
alternative to IOStreams.
|
||||
|
||||
`Documentation <http://fmtlib.net/latest/>`_
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Two APIs: faster concatenation-based write API and slower (but still
|
||||
very fast) replacement-based 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
|
||||
<http://fmtlib.net/latest/syntax.html>`_
|
||||
similar to the one used by `str.format
|
||||
<https://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python.
|
||||
* Safe `printf implementation
|
||||
<http://fmtlib.net/latest/api.html#printf-formatting-functions>`_
|
||||
including the POSIX extension for positional arguments.
|
||||
* 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
|
||||
`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
|
||||
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
|
||||
<https://github.com/fmtlib/fmt/tree/master/test>`_.
|
||||
* Safety: the library is fully type safe, errors in format strings are
|
||||
reported using exceptions, automatic memory management prevents buffer
|
||||
overflow errors.
|
||||
* Ease of use: small self-contained code base, no external dependencies,
|
||||
permissive BSD `license
|
||||
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_
|
||||
* `Portability <http://fmtlib.net/latest/index.html#portability>`_ with consistent output
|
||||
across platforms and support for older compilers.
|
||||
* Clean warning-free codebase even on high warning levels
|
||||
(-Wall -Wextra -pedantic).
|
||||
* Support for wide strings.
|
||||
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro.
|
||||
|
||||
See the `documentation <http://fmtlib.net/latest/>`_ for more details.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
This prints ``Hello, world!`` to stdout:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::print("Hello, {}!", "world"); // uses Python-like format string syntax
|
||||
fmt::printf("Hello, %s!", "world"); // uses printf format string syntax
|
||||
|
||||
Arguments can be accessed by position and arguments' indices can be repeated:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
std::string s = fmt::format("{0}{1}{0}", "abra", "cad");
|
||||
// s == "abracadabra"
|
||||
|
||||
fmt can be used as a safe portable replacement for ``itoa``:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::MemoryWriter w;
|
||||
w << 42; // replaces itoa(42, buffer, 10)
|
||||
w << fmt::hex(42); // replaces itoa(42, buffer, 16)
|
||||
// access the string using w.str() or w.c_str()
|
||||
|
||||
An object of any user-defined type for which there is an overloaded
|
||||
:code:`std::ostream` insertion operator (``operator<<``) can be formatted:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
public:
|
||||
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_;
|
||||
}
|
||||
};
|
||||
|
||||
std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
|
||||
// s == "The date is 2012-12-9"
|
||||
|
||||
You can use the `FMT_VARIADIC
|
||||
<http://fmtlib.net/latest/api.html#utilities>`_
|
||||
macro to create your own functions similar to `format
|
||||
<http://fmtlib.net/latest/api.html#format>`_ and
|
||||
`print <http://fmtlib.net/latest/api.html#print>`_
|
||||
which take arbitrary arguments:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
// Prints formatted error message.
|
||||
void report_error(const char *format, fmt::ArgList args) {
|
||||
fmt::print("Error: ");
|
||||
fmt::print(format, args);
|
||||
}
|
||||
FMT_VARIADIC(void, report_error, const char *)
|
||||
|
||||
report_error("file not found: {}", path);
|
||||
|
||||
Note that you only need to define one function that takes ``fmt::ArgList``
|
||||
argument. ``FMT_VARIADIC`` automatically defines necessary wrappers that
|
||||
accept variable number of arguments.
|
||||
|
||||
Projects using this library
|
||||
---------------------------
|
||||
|
||||
* `0 A.D. <http://play0ad.com/>`_: A free, open-source, cross-platform real-time strategy game
|
||||
|
||||
* `AMPL/MP <https://github.com/ampl/mp>`_:
|
||||
An open-source library for mathematical programming
|
||||
|
||||
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
||||
Player vs Player Gaming Network with tweaks
|
||||
|
||||
* `KBEngine <http://kbengine.org/>`_: An open-source MMOG server engine
|
||||
|
||||
* `Keypirinha <http://keypirinha.com/>`_: A semantic launcher for Windows
|
||||
|
||||
* `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
|
||||
|
||||
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
|
||||
An MMO server, compatible with most Ultima Online clients
|
||||
|
||||
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance, associative database
|
||||
|
||||
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
|
||||
|
||||
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster proxy
|
||||
|
||||
* `Saddy <https://github.com/mamontov-cpp/saddy-graphics-engine-2d>`_:
|
||||
Small crossplatform 2D graphic engine
|
||||
|
||||
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
|
||||
Business intelligence software
|
||||
|
||||
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
|
||||
|
||||
* `Stellar <https://www.stellar.org/>`_: Financial platform
|
||||
|
||||
* `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator
|
||||
|
||||
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source MMORPG framework
|
||||
|
||||
`More... <https://github.com/search?q=cppformat&type=Code>`_
|
||||
|
||||
If you are aware of other projects using this library, please let me know
|
||||
by `email <mailto:victor.zverovich@gmail.com>`_ or by submitting an
|
||||
`issue <https://github.com/fmtlib/fmt/issues>`_.
|
||||
|
||||
Motivation
|
||||
----------
|
||||
|
||||
So why yet another formatting library?
|
||||
|
||||
There are plenty of methods for doing this task, from standard ones like
|
||||
the printf family of function and IOStreams to Boost Format library and
|
||||
FastFormat. The reason for creating a new library is that every existing
|
||||
solution that I found either had serious issues or didn't provide
|
||||
all the features I needed.
|
||||
|
||||
Printf
|
||||
~~~~~~
|
||||
|
||||
The good thing about printf is that it is pretty fast and readily available
|
||||
being a part of the C standard library. The main drawback is that it
|
||||
doesn't support user-defined types. Printf also has safety issues although
|
||||
they are mostly solved with `__attribute__ ((format (printf, ...))
|
||||
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
|
||||
There is a POSIX extension that adds positional arguments required for
|
||||
`i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_
|
||||
to printf but it is not a part of C99 and may not be available on some
|
||||
platforms.
|
||||
|
||||
IOStreams
|
||||
~~~~~~~~~
|
||||
|
||||
The main issue with IOStreams is best illustrated with an example:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
|
||||
|
||||
which is a lot of typing compared to printf:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
printf("%.2f\n", 1.23456);
|
||||
|
||||
Matthew Wilson, the author of FastFormat, referred to this situation with
|
||||
IOStreams as "chevron hell". IOStreams doesn't support positional arguments
|
||||
by design.
|
||||
|
||||
The good part is that IOStreams supports user-defined types and is safe
|
||||
although error reporting is awkward.
|
||||
|
||||
Boost Format library
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is a very powerful library which supports both printf-like format
|
||||
strings and positional arguments. The main its drawback is performance.
|
||||
According to various benchmarks it is much slower than other methods
|
||||
considered here. Boost Format also has excessive build times and severe
|
||||
code bloat issues (see `Benchmarks`_).
|
||||
|
||||
FastFormat
|
||||
~~~~~~~~~~
|
||||
|
||||
This is an interesting library which is fast, safe and has positional
|
||||
arguments. However it has significant limitations, citing its author:
|
||||
|
||||
Three features that have no hope of being accommodated within the
|
||||
current design are:
|
||||
|
||||
* Leading zeros (or any other non-space padding)
|
||||
* Octal/hexadecimal encoding
|
||||
* Runtime width/alignment specification
|
||||
|
||||
It is also quite big and has a heavy dependency, STLSoft, which might be
|
||||
too restrictive for using it in some projects.
|
||||
|
||||
Loki SafeFormat
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
SafeFormat is a formatting library which uses printf-like format strings
|
||||
and is type safe. It doesn't support user-defined types or positional
|
||||
arguments. It makes unconventional use of ``operator()`` for passing
|
||||
format arguments.
|
||||
|
||||
Tinyformat
|
||||
~~~~~~~~~~
|
||||
|
||||
This library supports printf-like format strings and is very small and
|
||||
fast. Unfortunately it doesn't support positional arguments and wrapping
|
||||
it in C++98 is somewhat difficult. Also its performance and code compactness
|
||||
are limited by IOStreams.
|
||||
|
||||
Boost Spirit.Karma
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is not really a formatting library but I decided to include it here
|
||||
for completeness. As IOStreams it suffers from the problem of mixing
|
||||
verbatim text with arguments. The library is pretty fast, but slower
|
||||
on integer formatting than ``fmt::Writer`` on Karma's own benchmark,
|
||||
see `Fast integer to string conversion in C++
|
||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
||||
|
||||
Benchmarks
|
||||
----------
|
||||
|
||||
Speed tests
|
||||
~~~~~~~~~~~
|
||||
|
||||
The following speed tests results were generated by building
|
||||
``tinyformat_test.cpp`` on Ubuntu GNU/Linux 14.04.1 with
|
||||
``g++-4.8.2 -O3 -DSPEED_TEST -DHAVE_FORMAT``, and taking the best of three
|
||||
runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"`` or
|
||||
equivalent is filled 2000000 times with output sent to ``/dev/null``; for
|
||||
further details see the `source
|
||||
<https://github.com/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_.
|
||||
|
||||
================= ============= ===========
|
||||
Library Method Run Time, s
|
||||
================= ============= ===========
|
||||
EGLIBC 2.19 printf 1.30
|
||||
libstdc++ 4.8.2 std::ostream 1.85
|
||||
fmt 1.0 fmt::print 1.42
|
||||
tinyformat 2.0.1 tfm::printf 2.25
|
||||
Boost Format 1.54 boost::format 9.94
|
||||
================= ============= ===========
|
||||
|
||||
As you can see ``boost::format`` is much slower than the alternative methods; this
|
||||
is confirmed by `other tests <http://accu.org/index.php/journals/1539>`_.
|
||||
Tinyformat is quite good coming close to IOStreams. Unfortunately tinyformat
|
||||
cannot be faster than the IOStreams because it uses them internally.
|
||||
Performance of fmt is close to that of printf, being `faster than printf on integer
|
||||
formatting <http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_,
|
||||
but slower on floating-point formatting which dominates this benchmark.
|
||||
|
||||
Compile time and code bloat
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The script `bloat-test.py
|
||||
<https://github.com/fmtlib/format-benchmark/blob/master/bloat-test.py>`_
|
||||
from `format-benchmark <https://github.com/fmtlib/format-benchmark>`_
|
||||
tests compile time and code bloat for nontrivial projects.
|
||||
It generates 100 translation units and uses ``printf()`` or its alternative
|
||||
five times in each to simulate a medium sized project. The resulting
|
||||
executable size and compile time (g++-4.8.1, Ubuntu GNU/Linux 13.10,
|
||||
best of three) is shown in the following tables.
|
||||
|
||||
**Optimized build (-O3)**
|
||||
|
||||
============ =============== ==================== ==================
|
||||
Method Compile Time, s Executable size, KiB Stripped size, KiB
|
||||
============ =============== ==================== ==================
|
||||
printf 2.6 41 30
|
||||
IOStreams 19.4 92 70
|
||||
fmt 46.8 46 34
|
||||
tinyformat 64.6 418 386
|
||||
Boost Format 222.8 990 923
|
||||
============ =============== ==================== ==================
|
||||
|
||||
As you can see, fmt has two times less overhead in terms of resulting
|
||||
code size compared to IOStreams and comes pretty close to ``printf``.
|
||||
Boost Format has by far the largest overheads.
|
||||
|
||||
**Non-optimized build**
|
||||
|
||||
============ =============== ==================== ==================
|
||||
Method Compile Time, s Executable size, KiB Stripped size, KiB
|
||||
============ =============== ==================== ==================
|
||||
printf 2.1 41 30
|
||||
IOStreams 19.7 86 62
|
||||
fmt 47.9 108 86
|
||||
tinyformat 27.7 234 190
|
||||
Boost Format 122.6 884 763
|
||||
============ =============== ==================== ==================
|
||||
|
||||
``libc``, ``libstdc++`` and ``libfmt`` are all linked as shared
|
||||
libraries to compare formatting function overhead only. Boost Format
|
||||
and tinyformat are header-only libraries so they don't provide any
|
||||
linkage options.
|
||||
|
||||
Running the tests
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Please refer to `Building the library`__ for the instructions on how to build
|
||||
the library and run the unit tests.
|
||||
|
||||
__ http://fmtlib.net/latest/usage.html#building-the-library
|
||||
|
||||
Benchmarks reside in a separate repository,
|
||||
`format-benchmarks <https://github.com/fmtlib/format-benchmark>`_,
|
||||
so to run the benchmarks you first need to clone this repository and
|
||||
generate Makefiles with CMake::
|
||||
|
||||
$ git clone --recursive https://github.com/fmtlib/format-benchmark.git
|
||||
$ cd format-benchmark
|
||||
$ cmake .
|
||||
|
||||
Then you can run the speed test::
|
||||
|
||||
$ make speed-test
|
||||
|
||||
or the bloat test::
|
||||
|
||||
$ make bloat-test
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
fmt is distributed under the BSD `license
|
||||
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_.
|
||||
|
||||
The `Format String Syntax
|
||||
<http://fmtlib.net/latest/syntax.html>`_
|
||||
section in the documentation is based on the one from Python `string module
|
||||
documentation <https://docs.python.org/3/library/string.html#module-string>`_
|
||||
adapted for the current library. For this reason the documentation is
|
||||
distributed under the Python Software Foundation license available in
|
||||
`doc/python-license.txt
|
||||
<https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt>`_.
|
||||
It only applies if you distribute the documentation of fmt.
|
||||
|
||||
Acknowledgments
|
||||
---------------
|
||||
|
||||
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
|
||||
since it had some influence on tinyformat.
|
||||
Some ideas used in the implementation are borrowed from `Loki
|
||||
<http://loki-lib.sourceforge.net/>`_ SafeFormat and `Diagnostic API
|
||||
<http://clang.llvm.org/doxygen/classclang_1_1Diagnostic.html>`_ in
|
||||
`Clang <http://clang.llvm.org/>`_.
|
||||
Format string syntax and the documentation are based on Python's `str.format
|
||||
<http://docs.python.org/2/library/stdtypes.html#str.format>`_.
|
||||
Thanks `Doug Turnbull <https://github.com/softwaredoug>`_ for his valuable
|
||||
comments and contribution to the design of the type-safe API and
|
||||
`Gregory Czajkowski <https://github.com/gcflymoto>`_ for implementing binary
|
||||
formatting. Thanks `Ruslan Baratov <https://github.com/ruslo>`_ for comprehensive
|
||||
`comparison of integer formatting algorithms <https://github.com/ruslo/int-dec-format-tests>`_
|
||||
and useful comments regarding performance, `Boris Kaul <https://github.com/localvoid>`_ for
|
||||
`C++ counting digits benchmark <https://github.com/localvoid/cxx-benchmark-count-digits>`_.
|
||||
Thanks to `CarterLi <https://github.com/CarterLi>`_ for contributing various
|
||||
improvements to the code.
|
||||
2
libs/format/cppformat/format.h
Normal file
2
libs/format/cppformat/format.h
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../fmt/format.h"
|
||||
#warning Including cppformat/format.h is deprecated. Include fmt/format.h instead.
|
||||
2
libs/format/cppformat/posix.h
Normal file
2
libs/format/cppformat/posix.h
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../fmt/posix.h"
|
||||
#warning Including cppformat/posix.h is deprecated. Include fmt/posix.h instead.
|
||||
10
libs/format/doc/CMakeLists.txt
Normal file
10
libs/format/doc/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
find_program(DOXYGEN doxygen)
|
||||
if (NOT DOXYGEN)
|
||||
message(STATUS "Target 'doc' disabled (requires doxygen)")
|
||||
return ()
|
||||
endif ()
|
||||
|
||||
add_custom_target(doc
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION})
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/ DESTINATION share/doc/fmt)
|
||||
7
libs/format/doc/_static/bootstrap.min.js
vendored
Normal file
7
libs/format/doc/_static/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
libs/format/doc/_static/fonts/glyphicons-halflings-regular.eot
vendored
Normal file
BIN
libs/format/doc/_static/fonts/glyphicons-halflings-regular.eot
vendored
Normal file
Binary file not shown.
229
libs/format/doc/_static/fonts/glyphicons-halflings-regular.svg
vendored
Normal file
229
libs/format/doc/_static/fonts/glyphicons-halflings-regular.svg
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata></metadata>
|
||||
<defs>
|
||||
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
|
||||
<font-face units-per-em="1200" ascent="960" descent="-240" />
|
||||
<missing-glyph horiz-adv-x="500" />
|
||||
<glyph />
|
||||
<glyph />
|
||||
<glyph unicode="
" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
|
||||
<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="434" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="163" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="72" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode="€" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
|
||||
<glyph unicode="−" d="M200 400h900v300h-900v-300z" />
|
||||
<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" />
|
||||
<glyph unicode="☁" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
|
||||
<glyph unicode="✉" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
|
||||
<glyph unicode="✏" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
|
||||
<glyph unicode="" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
|
||||
<glyph unicode="" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
|
||||
<glyph unicode="" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
|
||||
<glyph unicode="" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
|
||||
<glyph unicode="" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
|
||||
<glyph unicode="" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
|
||||
<glyph unicode="" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
|
||||
<glyph unicode="" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
|
||||
<glyph unicode="" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
|
||||
<glyph unicode="" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
|
||||
<glyph unicode="" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
|
||||
<glyph unicode="" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
|
||||
<glyph unicode="" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
|
||||
<glyph unicode="" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
|
||||
<glyph unicode="" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
|
||||
<glyph unicode="" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
|
||||
<glyph unicode="" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
|
||||
<glyph unicode="" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
|
||||
<glyph unicode="" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
|
||||
<glyph unicode="" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
|
||||
<glyph unicode="" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
|
||||
<glyph unicode="" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
|
||||
<glyph unicode="" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
|
||||
<glyph unicode="" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
|
||||
<glyph unicode="" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
|
||||
<glyph unicode="" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
|
||||
<glyph unicode="" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
|
||||
<glyph unicode="" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
|
||||
<glyph unicode="" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
|
||||
<glyph unicode="" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
|
||||
<glyph unicode="" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
|
||||
<glyph unicode="" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
|
||||
<glyph unicode="" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
|
||||
<glyph unicode="" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
|
||||
<glyph unicode="" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
|
||||
<glyph unicode="" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
|
||||
<glyph unicode="" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
|
||||
<glyph unicode="" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
|
||||
<glyph unicode="" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
|
||||
<glyph unicode="" d="M200 0l900 550l-900 550v-1100z" />
|
||||
<glyph unicode="" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
|
||||
<glyph unicode="" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
|
||||
<glyph unicode="" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
|
||||
<glyph unicode="" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
|
||||
<glyph unicode="" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
|
||||
<glyph unicode="" d="M0 547l600 453v-300h600v-300h-600v-301z" />
|
||||
<glyph unicode="" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
|
||||
<glyph unicode="" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
|
||||
<glyph unicode="" d="M104 600h296v600h300v-600h298l-449 -600z" />
|
||||
<glyph unicode="" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
|
||||
<glyph unicode="" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
|
||||
<glyph unicode="" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
|
||||
<glyph unicode="" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
|
||||
<glyph unicode="" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
|
||||
<glyph unicode="" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
|
||||
<glyph unicode="" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
|
||||
<glyph unicode="" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
|
||||
<glyph unicode="" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
|
||||
<glyph unicode="" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
|
||||
<glyph unicode="" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
|
||||
<glyph unicode="" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
|
||||
<glyph unicode="" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
|
||||
<glyph unicode="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
|
||||
<glyph unicode="" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
|
||||
<glyph unicode="" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
|
||||
<glyph unicode="" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
|
||||
<glyph unicode="" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
|
||||
<glyph unicode="" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
|
||||
<glyph unicode="" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
|
||||
<glyph unicode="" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
|
||||
<glyph unicode="" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
|
||||
<glyph unicode="" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
|
||||
<glyph unicode="" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
|
||||
<glyph unicode="" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
|
||||
<glyph unicode="" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
|
||||
<glyph unicode="" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
|
||||
<glyph unicode="" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
|
||||
<glyph unicode="" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
|
||||
<glyph unicode="" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
|
||||
<glyph unicode="" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
|
||||
<glyph unicode="" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
|
||||
<glyph unicode="" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
|
||||
<glyph unicode="" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
|
||||
<glyph unicode="" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
|
||||
<glyph unicode="" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
|
||||
<glyph unicode="" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
|
||||
<glyph unicode="" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
|
||||
<glyph unicode="" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
|
||||
<glyph unicode="" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
|
||||
<glyph unicode="" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
|
||||
<glyph unicode="" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
|
||||
<glyph unicode="" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
|
||||
<glyph unicode="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
|
||||
<glyph unicode="" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 62 KiB |
BIN
libs/format/doc/_static/fonts/glyphicons-halflings-regular.ttf
vendored
Normal file
BIN
libs/format/doc/_static/fonts/glyphicons-halflings-regular.ttf
vendored
Normal file
Binary file not shown.
BIN
libs/format/doc/_static/fonts/glyphicons-halflings-regular.woff
vendored
Normal file
BIN
libs/format/doc/_static/fonts/glyphicons-halflings-regular.woff
vendored
Normal file
Binary file not shown.
138
libs/format/doc/_templates/layout.html
vendored
Normal file
138
libs/format/doc/_templates/layout.html
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
{% extends "!layout.html" %}
|
||||
|
||||
{% block extrahead %}
|
||||
<meta name="description" content="Small, safe and fast formatting library">
|
||||
<meta name="keywords" content="C++, formatting, printf, string, library">
|
||||
<meta name="author" content="Victor Zverovich">
|
||||
<link rel="stylesheet" href="_static/fmt.css">
|
||||
{# 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)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-20116650-4', 'fmtlib.net');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{%- macro searchform(classes, button) %}
|
||||
<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 }} >
|
||||
</div>
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
{% if button %}
|
||||
<input type="submit" class="btn btn-default" value="search">
|
||||
{% endif %}
|
||||
</form>
|
||||
{%- endmacro %}
|
||||
|
||||
{% block header %}
|
||||
<nav class="navbar navbar-inverse">
|
||||
<div class="tb-container">
|
||||
<div class="row">
|
||||
<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">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="index.html">{fmt}</a>
|
||||
</div>
|
||||
|
||||
{# Collect the nav links, forms, and other content for toggling #}
|
||||
<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>
|
||||
<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>
|
||||
</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>
|
||||
{%else%}
|
||||
<li><a href="{{name.lower()}}.html">{{name}}</a></li>
|
||||
{%endif%}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if pagename != 'search' %}
|
||||
{{ searchform('navbar-form navbar-right', False) }}
|
||||
{%endif%}
|
||||
</div> {# /.navbar-collapse #}
|
||||
</div> {# /.col-md-offset-2 #}
|
||||
</div> {# /.row #}
|
||||
</div> {# /.tb-container #}
|
||||
</nav>
|
||||
{% if pagename == "index" %}
|
||||
<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
|
||||
</a>
|
||||
<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>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{# Disable relbars. #}
|
||||
{% block relbar1 %}
|
||||
{% endblock %}
|
||||
{% block relbar2 %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="tb-container">
|
||||
<div class="row">
|
||||
{# TODO: integrate sidebar
|
||||
<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"/>
|
||||
</a></p>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- for sidebartemplate in sidebars %}
|
||||
{%- include sidebartemplate %}
|
||||
{%- endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
#}
|
||||
|
||||
<div class="content">
|
||||
{% block body %} {% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
{{ super() }}
|
||||
{# Placed at the end of the document so the pages load faster. #}
|
||||
<script src="_static/bootstrap.min.js"></script>
|
||||
{% endblock %}
|
||||
55
libs/format/doc/_templates/search.html
vendored
Normal file
55
libs/format/doc/_templates/search.html
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
{#
|
||||
basic/search.html
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Template for the search page.
|
||||
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{%- extends "layout.html" %}
|
||||
{% set title = _('Search') %}
|
||||
{% set script_files = script_files + ['_static/searchtools.js'] %}
|
||||
{% block extrahead %}
|
||||
<script type="text/javascript">
|
||||
jQuery(function() { Search.loadIndex("{{ pathto('searchindex.js', 1) }}"); });
|
||||
</script>
|
||||
{# this is used when loading the search index using $.ajax fails,
|
||||
such as on Chrome for documents on localhost #}
|
||||
<script type="text/javascript" id="searchindexloader"></script>
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<h1 id="search-documentation">{{ _('Search') }}</h1>
|
||||
<div id="fallback" class="admonition warning">
|
||||
<script type="text/javascript">$('#fallback').hide();</script>
|
||||
<p>
|
||||
{% trans %}Please activate JavaScript to enable the search
|
||||
functionality.{% endtrans %}
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
{% trans %}From here you can search these documents. Enter your search
|
||||
words into the box below and click "search". Note that the search
|
||||
function will automatically search for all of the words. Pages
|
||||
containing fewer words won't appear in the result list.{% endtrans %}
|
||||
</p>
|
||||
{{ searchform('form-inline', True) }}
|
||||
{% if search_performed %}
|
||||
<h2>{{ _('Search Results') }}</h2>
|
||||
{% if not search_results %}
|
||||
<p>{{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div id="search-results">
|
||||
{% if search_results %}
|
||||
<ul>
|
||||
{% for href, caption, context in search_results %}
|
||||
<li><a href="{{ pathto(item.href) }}">{{ caption }}</a>
|
||||
<div class="context">{{ context|e }}</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
213
libs/format/doc/api.rst
Normal file
213
libs/format/doc/api.rst
Normal file
@ -0,0 +1,213 @@
|
||||
.. _string-formatting-api:
|
||||
|
||||
*************
|
||||
API Reference
|
||||
*************
|
||||
|
||||
All functions and classes provided by the fmt library reside
|
||||
in namespace ``fmt`` and macros have prefix ``FMT_``. For brevity the
|
||||
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
|
||||
<http://docs.python.org/3/library/stdtypes.html#str.format>`_ function.
|
||||
They take *format_str* and *args* as arguments.
|
||||
|
||||
*format_str* is a format string that contains literal text and replacement
|
||||
fields surrounded by braces ``{}``. The fields are replaced with formatted
|
||||
arguments in the resulting string.
|
||||
|
||||
*args* is an argument list representing arbitrary arguments.
|
||||
|
||||
.. _format:
|
||||
|
||||
.. doxygenfunction:: format(CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: operator""_format(const char *, std::size_t)
|
||||
|
||||
.. _print:
|
||||
|
||||
.. doxygenfunction:: print(CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: print(std::FILE *, CStringRef, ArgList)
|
||||
|
||||
.. doxygenclass:: fmt::BasicFormatter
|
||||
:members:
|
||||
|
||||
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"
|
||||
|
||||
std::time_t t = std::time(nullptr);
|
||||
// Prints "The date is 2016-04-29." (with the current date)
|
||||
fmt::print("The date is {:%Y-%m-%d}.", *std::localtime(&t));
|
||||
|
||||
The format string syntax is described in the documentation of
|
||||
`strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_.
|
||||
|
||||
``std::ostream`` support
|
||||
------------------------
|
||||
|
||||
The header ``fmt/ostream.h`` provides ``std::ostream`` support including
|
||||
formatting of user-defined types that have overloaded ``operator<<``::
|
||||
|
||||
#include "fmt/ostream.h"
|
||||
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
public:
|
||||
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_;
|
||||
}
|
||||
};
|
||||
|
||||
std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
|
||||
// s == "The date is 2012-12-9"
|
||||
|
||||
.. doxygenfunction:: print(std::ostream&, CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList)
|
||||
|
||||
Argument formatters
|
||||
-------------------
|
||||
|
||||
It is possible to change the way arguments are formatted by providing a
|
||||
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:
|
||||
CustomArgFormatter(fmt::BasicFormatter<char, CustomArgFormatter> &f,
|
||||
fmt::FormatSpec &s, const char *fmt)
|
||||
: fmt::BasicArgFormatter<CustomArgFormatter, char>(f, s, fmt) {}
|
||||
|
||||
void visit_int(int value) {
|
||||
if (spec().type() == 'x')
|
||||
visit_uint(value); // convert to unsigned and format
|
||||
else
|
||||
fmt::BasicArgFormatter<CustomArgFormatter, char>::visit_int(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 s = custom_format("{:x}", -42); // s == "ffffffd6"
|
||||
|
||||
.. doxygenclass:: fmt::ArgVisitor
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicArgFormatter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::ArgFormatter
|
||||
:members:
|
||||
|
||||
Printf formatting functions
|
||||
---------------------------
|
||||
|
||||
The following functions use `printf format string syntax
|
||||
<http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>`_ with
|
||||
a POSIX extension for positional arguments.
|
||||
|
||||
.. doxygenfunction:: printf(CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fprintf(std::FILE *, CStringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: sprintf(CStringRef, ArgList)
|
||||
|
||||
Write API
|
||||
=========
|
||||
|
||||
.. doxygenclass:: fmt::BasicWriter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicMemoryWriter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicArrayWriter
|
||||
:members:
|
||||
|
||||
.. doxygenfunction:: bin(int)
|
||||
|
||||
.. doxygenfunction:: oct(int)
|
||||
|
||||
.. doxygenfunction:: hex(int)
|
||||
|
||||
.. doxygenfunction:: hexu(int)
|
||||
|
||||
.. doxygenfunction:: pad(int, unsigned, Char)
|
||||
|
||||
Utilities
|
||||
=========
|
||||
|
||||
.. doxygenfunction:: fmt::arg(StringRef, const T&)
|
||||
|
||||
.. doxygenfunction:: operator""_a(const char *, std::size_t)
|
||||
|
||||
.. doxygendefine:: FMT_CAPTURE
|
||||
|
||||
.. doxygendefine:: FMT_VARIADIC
|
||||
|
||||
.. doxygenclass:: fmt::ArgList
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicStringRef
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicCStringRef
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::Buffer
|
||||
:protected-members:
|
||||
:members:
|
||||
|
||||
System errors
|
||||
=============
|
||||
|
||||
.. doxygenclass:: fmt::SystemError
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::WindowsError
|
||||
:members:
|
||||
|
||||
.. _formatstrings:
|
||||
|
||||
Custom allocators
|
||||
=================
|
||||
|
||||
The fmt library supports custom dynamic memory allocators.
|
||||
A custom allocator class can be specified as a template argument to
|
||||
:class:`fmt::BasicMemoryWriter`::
|
||||
|
||||
typedef fmt::BasicMemoryWriter<char, CustomAllocator> CustomMemoryWriter;
|
||||
|
||||
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;
|
||||
|
||||
CustomString format(CustomAllocator alloc, fmt::CStringRef format_str,
|
||||
fmt::ArgList args) {
|
||||
CustomMemoryWriter writer(alloc);
|
||||
writer.write(format_str, args);
|
||||
return CustomString(writer.data(), writer.size(), alloc);
|
||||
}
|
||||
FMT_VARIADIC(CustomString, format, CustomAllocator, fmt::CStringRef)
|
||||
2
libs/format/doc/basic-bootstrap/README
Normal file
2
libs/format/doc/basic-bootstrap/README
Normal file
@ -0,0 +1,2 @@
|
||||
Sphinx basic theme with Bootstrap support. Modifications are kept to
|
||||
a minimum to simplify integration in case of changes to Sphinx theming.
|
||||
205
libs/format/doc/basic-bootstrap/layout.html
Normal file
205
libs/format/doc/basic-bootstrap/layout.html
Normal file
@ -0,0 +1,205 @@
|
||||
{#
|
||||
basic/layout.html
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Master layout template for Sphinx themes.
|
||||
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{%- block doctype -%}
|
||||
<!DOCTYPE html>
|
||||
{%- endblock %}
|
||||
{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %}
|
||||
{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}
|
||||
{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and
|
||||
(sidebars != []) %}
|
||||
{%- set url_root = pathto('', 1) %}
|
||||
{# XXX necessary? #}
|
||||
{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
|
||||
{%- if not embedded and docstitle %}
|
||||
{%- set titlesuffix = " — "|safe + docstitle|e %}
|
||||
{%- else %}
|
||||
{%- set titlesuffix = "" %}
|
||||
{%- endif %}
|
||||
|
||||
{%- macro relbar() %}
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>{{ _('Navigation') }}</h3>
|
||||
<ul>
|
||||
{%- for rellink in rellinks %}
|
||||
<li class="right" {% if loop.first %}style="margin-right: 10px"{% endif %}>
|
||||
<a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
|
||||
{{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
|
||||
{%- if not loop.first %}{{ reldelim2 }}{% endif %}</li>
|
||||
{%- endfor %}
|
||||
{%- block rootrellink %}
|
||||
<li class="nav-item nav-item-0"><a href="{{ pathto(master_doc) }}">{{ shorttitle|e }}</a>{{ reldelim1 }}</li>
|
||||
{%- endblock %}
|
||||
{%- for parent in parents %}
|
||||
<li class="nav-item nav-item-{{ loop.index }}"><a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a>{{ reldelim1 }}</li>
|
||||
{%- endfor %}
|
||||
{%- block relbaritems %} {% endblock %}
|
||||
</ul>
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro sidebar() %}
|
||||
{%- if render_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"/>
|
||||
</a></p>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- if sidebars != None %}
|
||||
{#- new style sidebar: explicitly include/exclude templates #}
|
||||
{%- for sidebartemplate in sidebars %}
|
||||
{%- include sidebartemplate %}
|
||||
{%- endfor %}
|
||||
{%- else %}
|
||||
{#- old style sidebars: using blocks -- should be deprecated #}
|
||||
{%- block sidebartoc %}
|
||||
{%- include "localtoc.html" %}
|
||||
{%- endblock %}
|
||||
{%- block sidebarrel %}
|
||||
{%- include "relations.html" %}
|
||||
{%- endblock %}
|
||||
{%- block sidebarsourcelink %}
|
||||
{%- include "sourcelink.html" %}
|
||||
{%- endblock %}
|
||||
{%- if customsidebar %}
|
||||
{%- include customsidebar %}
|
||||
{%- endif %}
|
||||
{%- block sidebarsearch %}
|
||||
{%- include "searchbox.html" %}
|
||||
{%- endblock %}
|
||||
{%- endif %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro script() %}
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '{{ url_root }}',
|
||||
VERSION: '{{ release|e }}',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
|
||||
HAS_SOURCE: {{ has_source|lower }}
|
||||
};
|
||||
</script>
|
||||
{%- for scriptfile in script_files %}
|
||||
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
|
||||
{%- endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro css() %}
|
||||
<link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
|
||||
{%- for cssfile in css_files %}
|
||||
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||
{%- endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="{{ encoding }}">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
{# The above 3 meta tags *must* come first in the head; any other head content
|
||||
must come *after* these tags. #}
|
||||
{{ metatags }}
|
||||
{%- block htmltitle %}
|
||||
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
|
||||
{%- endblock %}
|
||||
{{ css() }}
|
||||
{%- if not embedded %}
|
||||
{{ script() }}
|
||||
{%- if use_opensearch %}
|
||||
<link rel="search" type="application/opensearchdescription+xml"
|
||||
title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}"
|
||||
href="{{ pathto('_static/opensearch.xml', 1) }}"/>
|
||||
{%- endif %}
|
||||
{%- if favicon %}
|
||||
<link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{%- block linktags %}
|
||||
{%- if hasdoc('about') %}
|
||||
<link rel="author" title="{{ _('About these documents') }}" href="{{ pathto('about') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('genindex') %}
|
||||
<link rel="index" title="{{ _('Index') }}" href="{{ pathto('genindex') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('search') %}
|
||||
<link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('copyright') %}
|
||||
<link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
|
||||
{%- endif %}
|
||||
{%- if parents %}
|
||||
<link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}" />
|
||||
{%- endif %}
|
||||
{%- if next %}
|
||||
<link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}" />
|
||||
{%- endif %}
|
||||
{%- if prev %}
|
||||
<link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}" />
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- block extrahead %} {% endblock %}
|
||||
</head>
|
||||
<body role="document">
|
||||
{%- block header %}{% endblock %}
|
||||
|
||||
{%- block relbar1 %}{{ relbar() }}{% endblock %}
|
||||
|
||||
{%- block content %}
|
||||
{%- block sidebar1 %} {# possible location for sidebar #} {% endblock %}
|
||||
|
||||
<div class="document">
|
||||
{%- block document %}
|
||||
<div class="documentwrapper">
|
||||
{%- if render_sidebar %}
|
||||
<div class="bodywrapper">
|
||||
{%- endif %}
|
||||
<div class="body" role="main">
|
||||
{% block body %} {% endblock %}
|
||||
</div>
|
||||
{%- if render_sidebar %}
|
||||
</div>
|
||||
{%- endif %}
|
||||
</div>
|
||||
{%- endblock %}
|
||||
|
||||
{%- block sidebar2 %}{{ sidebar() }}{% endblock %}
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
{%- endblock %}
|
||||
|
||||
{%- block relbar2 %}{{ relbar() }}{% endblock %}
|
||||
|
||||
{%- block footer %}
|
||||
<div class="footer" role="contentinfo">
|
||||
{%- if show_copyright %}
|
||||
{%- if hasdoc('copyright') %}
|
||||
{% trans path=pathto('copyright'), copyright=copyright|e %}© <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}
|
||||
{%- else %}
|
||||
{% trans copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %}
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{%- if last_updated %}
|
||||
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
|
||||
{%- endif %}
|
||||
{%- if show_sphinx %}
|
||||
{% trans sphinx_version=sphinx_version|e %}Created using <a href="http://sphinx-doc.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %}
|
||||
{%- endif %}
|
||||
</div>
|
||||
{%- endblock %}
|
||||
</body>
|
||||
</html>
|
||||
2
libs/format/doc/basic-bootstrap/theme.conf
Normal file
2
libs/format/doc/basic-bootstrap/theme.conf
Normal file
@ -0,0 +1,2 @@
|
||||
[theme]
|
||||
inherit = basic
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user