Skip to content

Commit bd839cc

Browse files
committed
Merge branch 'develop' for 1.2.1
2 parents 42a45b6 + 1e5e648 commit bd839cc

31 files changed

+406
-174
lines changed

CMakeLists.txt

+8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.0) # installing cereal requires INTERFACE li
66
option(JUST_INSTALL_CEREAL "Don't do anything besides installing the library" OFF)
77
endif()
88

9+
option(THREAD_SAFE "Use mutexes to ensure thread safety" OFF)
10+
if(THREAD_SAFE)
11+
add_definitions(-DCEREAL_THREAD_SAFE=1)
12+
set(CEREAL_THREAD_LIBS "pthread")
13+
else()
14+
set(CEREAL_THREAD_LIBS "")
15+
endif()
16+
917
if(NOT MSVC)
1018
set(CMAKE_CXX_FLAGS "-Wall -Werror -g -Wextra -Wshadow -pedantic ${CMAKE_CXX_FLAGS}")
1119
if(CMAKE_VERSION VERSION_LESS 3.1)

include/cereal/archives/binary.hpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ namespace cereal
5959
itsStream(stream)
6060
{ }
6161

62+
~BinaryOutputArchive() CEREAL_NOEXCEPT = default;
63+
6264
//! Writes size bytes of data to the output stream
6365
void saveBinary( const void * data, std::size_t size )
6466
{
@@ -90,7 +92,9 @@ namespace cereal
9092
BinaryInputArchive(std::istream & stream) :
9193
InputArchive<BinaryInputArchive, AllowEmptyClassElision>(this),
9294
itsStream(stream)
93-
{ }
95+
{ }
96+
97+
~BinaryInputArchive() CEREAL_NOEXCEPT = default;
9498

9599
//! Reads size bytes of data from the input stream
96100
void loadBinary( void * const data, std::size_t size )

include/cereal/archives/json.hpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ namespace cereal
4646
throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); }
4747
#endif // RAPIDJSON_ASSERT
4848

49+
// Enable support for parsing of nan, inf, -inf
50+
#define CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag
51+
#define CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag | kParseNanAndInfFlag
52+
4953
#include <cereal/external/rapidjson/prettywriter.h>
5054
#include <cereal/external/rapidjson/ostreamwrapper.h>
5155
#include <cereal/external/rapidjson/istreamwrapper.h>
@@ -155,7 +159,7 @@ namespace cereal
155159
}
156160

157161
//! Destructor, flushes the JSON
158-
~JSONOutputArchive()
162+
~JSONOutputArchive() CEREAL_NOEXCEPT
159163
{
160164
if (itsNodeStack.top() == NodeType::InObject)
161165
itsWriter.EndObject();
@@ -420,13 +424,15 @@ namespace cereal
420424
itsNextName( nullptr ),
421425
itsReadStream(stream)
422426
{
423-
itsDocument.ParseStream<rapidjson::kParseFullPrecisionFlag>(itsReadStream);
427+
itsDocument.ParseStream<>(itsReadStream);
424428
if (itsDocument.IsArray())
425429
itsIteratorStack.emplace_back(itsDocument.Begin(), itsDocument.End());
426430
else
427431
itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
428432
}
429433

434+
~JSONInputArchive() CEREAL_NOEXCEPT = default;
435+
430436
//! Loads some binary data, encoded as a base64 string
431437
/*! This will automatically start and finish a node to load the data, and can be called directly by
432438
users.

include/cereal/archives/portable_binary.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ namespace cereal
125125
this->operator()( options.is_little_endian() );
126126
}
127127

128+
~PortableBinaryOutputArchive() CEREAL_NOEXCEPT = default;
129+
128130
//! Writes size bytes of data to the output stream
129131
template <std::size_t DataSize> inline
130132
void saveBinary( const void * data, std::size_t size )
@@ -227,6 +229,8 @@ namespace cereal
227229
itsConvertEndianness = options.is_little_endian() ^ streamLittleEndian;
228230
}
229231

232+
~PortableBinaryInputArchive() CEREAL_NOEXCEPT = default;
233+
230234
//! Reads size bytes of data from the input stream
231235
/*! @param data The data to save
232236
@param size The number of bytes in the data

include/cereal/archives/xml.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ namespace cereal
158158
}
159159

160160
//! Destructor, flushes the XML
161-
~XMLOutputArchive()
161+
~XMLOutputArchive() CEREAL_NOEXCEPT
162162
{
163163
const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
164164
rapidxml::print( itsStream, itsXML, flags );
@@ -412,6 +412,8 @@ namespace cereal
412412
itsNodes.emplace( root );
413413
}
414414

415+
~XMLInputArchive() CEREAL_NOEXCEPT = default;
416+
415417
//! Loads some binary data, encoded as a base64 string, optionally specified by some name
416418
/*! This will automatically start and finish a node to load the data, and can be called directly by
417419
users.

include/cereal/cereal.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ namespace cereal
476476
{
477477
static const auto hash = std::type_index(typeid(T)).hash_code();
478478
const auto insertResult = itsVersionedTypes.insert( hash );
479+
const auto lock = detail::StaticObject<detail::Versions>::lock();
479480
const auto version =
480481
detail::StaticObject<detail::Versions>::getInstance().find( hash, detail::Version<T>::version );
481482

include/cereal/details/helpers.hpp

-24
Original file line numberDiff line numberDiff line change
@@ -40,30 +40,6 @@
4040
#include <cereal/macros.hpp>
4141
#include <cereal/details/static_object.hpp>
4242

43-
//! Defines the CEREAL_NOEXCEPT macro to use instead of noexcept
44-
/*! If a compiler we support does not support noexcept, this macro
45-
will detect this and define CEREAL_NOEXCEPT as a no-op */
46-
#if !defined(CEREAL_HAS_NOEXCEPT)
47-
#if defined(__clang__)
48-
#if __has_feature(cxx_noexcept)
49-
#define CEREAL_HAS_NOEXCEPT
50-
#endif
51-
#else // NOT clang
52-
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
53-
defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
54-
#define CEREAL_HAS_NOEXCEPT
55-
#endif // end GCC/MSVC check
56-
#endif // end NOT clang block
57-
58-
#ifndef CEREAL_NOEXCEPT
59-
#ifdef CEREAL_HAS_NOEXCEPT
60-
#define CEREAL_NOEXCEPT noexcept
61-
#else
62-
#define CEREAL_NOEXCEPT
63-
#endif // end CEREAL_HAS_NOEXCEPT
64-
#endif // end !defined(CEREAL_HAS_NOEXCEPT)
65-
#endif // ifndef CEREAL_NOEXCEPT
66-
6743
namespace cereal
6844
{
6945
// ######################################################################

include/cereal/details/polymorphic_impl.hpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ namespace cereal
128128
static bool exists( std::type_index const & baseIndex, std::type_index const & derivedIndex )
129129
{
130130
// First phase of lookup - match base type index
131-
auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
131+
auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
132132
auto baseIter = baseMap.find( baseIndex );
133133
if (baseIter == baseMap.end())
134134
return false;
@@ -151,7 +151,7 @@ namespace cereal
151151
static std::vector<PolymorphicCaster const *> const & lookup( std::type_index const & baseIndex, std::type_index const & derivedIndex, F && exceptionFunc )
152152
{
153153
// First phase of lookup - match base type index
154-
auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
154+
auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
155155
auto baseIter = baseMap.find( baseIndex );
156156
if( baseIter == baseMap.end() )
157157
exceptionFunc();
@@ -161,7 +161,7 @@ namespace cereal
161161
auto derivedIter = derivedMap.find( derivedIndex );
162162
if( derivedIter == derivedMap.end() )
163163
exceptionFunc();
164-
164+
165165
return derivedIter->second;
166166
}
167167

@@ -218,6 +218,7 @@ namespace cereal
218218
assuming dynamic type information is available */
219219
PolymorphicVirtualCaster()
220220
{
221+
const auto lock = StaticObject<PolymorphicCasters>::lock();
221222
auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
222223
auto baseKey = std::type_index(typeid(Base));
223224
auto lb = baseMap.lower_bound(baseKey);
@@ -236,7 +237,7 @@ namespace cereal
236237
auto checkRelation = [](std::type_index const & baseInfo, std::type_index const & derivedInfo)
237238
{
238239
const bool exists = PolymorphicCasters::exists( baseInfo, derivedInfo );
239-
return std::make_pair( exists, exists ? PolymorphicCasters::lookup( baseInfo, derivedInfo, [](){} ) :
240+
return std::make_pair( exists, exists ? PolymorphicCasters::lookup( baseInfo, derivedInfo, [](){} ) :
240241
std::vector<PolymorphicCaster const *>{} );
241242
};
242243

@@ -409,6 +410,7 @@ namespace cereal
409410
InputBindingCreator()
410411
{
411412
auto & map = StaticObject<InputBindingMap<Archive>>::getInstance().map;
413+
auto lock = StaticObject<InputBindingMap<Archive>>::lock();
412414
auto key = std::string(binding_name<T>::name());
413415
auto lb = map.lower_bound(key);
414416

include/cereal/details/static_object.hpp

+43-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@
2828
#ifndef CEREAL_DETAILS_STATIC_OBJECT_HPP_
2929
#define CEREAL_DETAILS_STATIC_OBJECT_HPP_
3030

31+
#include <cereal/macros.hpp>
32+
33+
#if CEREAL_THREAD_SAFE
34+
#include <mutex>
35+
#endif
36+
3137
//! Prevent link optimization from removing non-referenced static objects
3238
/*! Especially for polymorphic support, we create static objects which
3339
may not ever be explicitly referenced. Most linkers will detect this
@@ -79,12 +85,48 @@ namespace cereal
7985
return create();
8086
}
8187

88+
//! A class that acts like std::lock_guard
89+
class LockGuard
90+
{
91+
#if CEREAL_THREAD_SAFE
92+
public:
93+
LockGuard(std::mutex & m) : lock(m) {}
94+
private:
95+
std::unique_lock<std::mutex> lock;
96+
#else
97+
public:
98+
~LockGuard() CEREAL_NOEXCEPT {} // prevents variable not used
99+
#endif
100+
};
101+
102+
//! Attempts to lock this static object for the current scope
103+
/*! @note This function is a no-op if cereal is not compiled with
104+
thread safety enabled (CEREAL_THREAD_SAFE = 1).
105+
106+
This function returns an object that holds a lock for
107+
this StaticObject that will release its lock upon destruction. This
108+
call will block until the lock is available. */
109+
static LockGuard lock()
110+
{
111+
#if CEREAL_THREAD_SAFE
112+
return LockGuard{instanceMutex};
113+
#else
114+
return LockGuard{};
115+
#endif
116+
}
117+
82118
private:
83119
static T & instance;
120+
#if CEREAL_THREAD_SAFE
121+
static std::mutex instanceMutex;
122+
#endif
84123
};
85124

86125
template <class T> T & StaticObject<T>::instance = StaticObject<T>::create();
126+
#if CEREAL_THREAD_SAFE
127+
template <class T> std::mutex StaticObject<T>::instanceMutex;
128+
#endif
87129
} // namespace detail
88130
} // namespace cereal
89131

90-
#endif // CEREAL_DETAILS_STATIC_OBJECT_HPP_
132+
#endif // CEREAL_DETAILS_STATIC_OBJECT_HPP_

include/cereal/external/rapidjson/allocators.h

+20-12
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ class MemoryPoolAllocator {
179179

180180
size = CEREAL_RAPIDJSON_ALIGN(size);
181181
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
182-
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
182+
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
183+
return NULL;
183184

184185
void *buffer = reinterpret_cast<char *>(chunkHead_) + CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
185186
chunkHead_->size += size;
@@ -211,11 +212,13 @@ class MemoryPoolAllocator {
211212
}
212213

213214
// Realloc process: allocate and copy memory, do not free original buffer.
214-
void* newBuffer = Malloc(newSize);
215-
CEREAL_RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
216-
if (originalSize)
217-
std::memcpy(newBuffer, originalPtr, originalSize);
218-
return newBuffer;
215+
if (void* newBuffer = Malloc(newSize)) {
216+
if (originalSize)
217+
std::memcpy(newBuffer, originalPtr, originalSize);
218+
return newBuffer;
219+
}
220+
else
221+
return NULL;
219222
}
220223

221224
//! Frees a memory block (concept Allocator)
@@ -229,15 +232,20 @@ class MemoryPoolAllocator {
229232

230233
//! Creates a new chunk.
231234
/*! \param capacity Capacity of the chunk in bytes.
235+
\return true if success.
232236
*/
233-
void AddChunk(size_t capacity) {
237+
bool AddChunk(size_t capacity) {
234238
if (!baseAllocator_)
235239
ownBaseAllocator_ = baseAllocator_ = CEREAL_RAPIDJSON_NEW(BaseAllocator());
236-
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));
237-
chunk->capacity = capacity;
238-
chunk->size = 0;
239-
chunk->next = chunkHead_;
240-
chunkHead_ = chunk;
240+
if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
241+
chunk->capacity = capacity;
242+
chunk->size = 0;
243+
chunk->next = chunkHead_;
244+
chunkHead_ = chunk;
245+
return true;
246+
}
247+
else
248+
return false;
241249
}
242250

243251
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.

0 commit comments

Comments
 (0)