-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Optimize copy / assignment and size of json iterator
- Loading branch information
Showing
8 changed files
with
1,256 additions
and
989 deletions.
There are no files selected for viewing
186 changes: 176 additions & 10 deletions
186
include/nlohmann/detail/iterators/internal_iterator.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,191 @@ | ||
#pragma once | ||
|
||
#include <cassert> | ||
#include <cstdint> | ||
#include <type_traits> | ||
#include <utility> | ||
|
||
#include <nlohmann/detail/iterators/primitive_iterator.hpp> | ||
#include <nlohmann/detail/meta/memory.hpp> | ||
|
||
namespace nlohmann | ||
{ | ||
namespace detail | ||
{ | ||
|
||
template<class BasicJsonType> | ||
class internal_iterator_base | ||
{ | ||
public: | ||
using ObjectIterator = typename BasicJsonType::object_t::iterator; | ||
using ArrayIterator = typename BasicJsonType::array_t::iterator; | ||
|
||
ObjectIterator& object_iterator() | ||
{ | ||
return *reinterpret_cast<ObjectIterator*>(&m_data); | ||
} | ||
ObjectIterator object_iterator() const | ||
{ | ||
return *reinterpret_cast<const ObjectIterator*>(&m_data); | ||
} | ||
|
||
ArrayIterator& array_iterator() | ||
{ | ||
return *reinterpret_cast<ArrayIterator*>(&m_data); | ||
} | ||
ArrayIterator array_iterator() const | ||
{ | ||
return *reinterpret_cast<const ArrayIterator*>(&m_data); | ||
} | ||
|
||
primitive_iterator_t& primitive_iterator() | ||
{ | ||
return *reinterpret_cast<primitive_iterator_t*>(&m_data); | ||
} | ||
primitive_iterator_t primitive_iterator() const | ||
{ | ||
return *reinterpret_cast<const primitive_iterator_t*>(&m_data); | ||
} | ||
|
||
private: | ||
// take the maximum size of all three iterators | ||
static constexpr std::size_t kMaxIteratorSize = sizeof(ObjectIterator) < sizeof(ArrayIterator) ? (sizeof(ArrayIterator) < sizeof(primitive_iterator_t) | ||
? sizeof(primitive_iterator_t) | ||
: sizeof(ArrayIterator)) | ||
: (sizeof(ObjectIterator) < sizeof(primitive_iterator_t) | ||
? sizeof(primitive_iterator_t) | ||
: sizeof(ObjectIterator)); | ||
|
||
// take the maximum alignment of all three iterators | ||
static constexpr std::size_t kMaxIteratorAlignment = std::alignment_of<ObjectIterator>::value < std::alignment_of<ArrayIterator>::value ? (std::alignment_of<ArrayIterator>::value < std::alignment_of<primitive_iterator_t>::value | ||
? std::alignment_of<primitive_iterator_t>::value | ||
: std::alignment_of<ArrayIterator>::value) | ||
: (std::alignment_of<ObjectIterator>::value < std::alignment_of<primitive_iterator_t>::value | ||
? std::alignment_of<primitive_iterator_t>::value | ||
: std::alignment_of<ObjectIterator>::value); | ||
|
||
protected: | ||
alignas(kMaxIteratorAlignment) std::uint8_t m_data[kMaxIteratorSize]; | ||
}; | ||
|
||
/*! | ||
@brief an iterator value | ||
@brief Implementation of internal_iterator for non trivially destructible types | ||
*/ | ||
template<class BasicJsonType, bool trivially_destructible> | ||
class internal_iterator_impl : public internal_iterator_base<BasicJsonType> | ||
{ | ||
public: | ||
using ObjectIterator = typename BasicJsonType::object_t::iterator; | ||
using ArrayIterator = typename BasicJsonType::array_t::iterator; | ||
|
||
internal_iterator_impl() noexcept = default; | ||
|
||
~internal_iterator_impl() | ||
{ | ||
// We call the destructor of the underlying initialized object | ||
switch (m_it_type) | ||
{ | ||
case 0: | ||
nlohmann::detail::destroy_at(reinterpret_cast<ObjectIterator*>(&this->m_data)); | ||
break; | ||
case 1: | ||
nlohmann::detail::destroy_at(reinterpret_cast<ArrayIterator*>(&this->m_data)); | ||
break; | ||
case 2: | ||
nlohmann::detail::destroy_at(reinterpret_cast<primitive_iterator_t*>(&this->m_data)); | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
void init_object_iterator() | ||
{ | ||
assert(m_it_type == -1); | ||
m_it_type = 0; | ||
new (reinterpret_cast<ObjectIterator*>(&this->m_data)) ObjectIterator(); | ||
} | ||
|
||
template<class ObjIt> | ||
void set_object_iterator(ObjIt&& it) | ||
{ | ||
assert(m_it_type == 0); | ||
// Object iterator already constructed - use move assignment | ||
*reinterpret_cast<ObjectIterator*>(&this->m_data) = std::forward<ObjIt>(it); | ||
} | ||
|
||
@note This structure could easily be a union, but MSVC currently does not allow | ||
unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. | ||
void init_array_iterator() | ||
{ | ||
assert(m_it_type == -1); | ||
m_it_type = 1; | ||
new (reinterpret_cast<ArrayIterator*>(&this->m_data)) ArrayIterator(); | ||
} | ||
|
||
template<class ArrIt> | ||
void set_array_iterator(ArrIt&& it) | ||
{ | ||
assert(m_it_type == 1); | ||
// Array iterator already constructed - use move assignment | ||
*reinterpret_cast<ArrayIterator*>(&this->m_data) = std::forward<ArrIt>(it); | ||
} | ||
|
||
void init_primitive_iterator() | ||
{ | ||
assert(m_it_type == -1); | ||
m_it_type = 2; | ||
new (reinterpret_cast<primitive_iterator_t*>(&this->m_data)) primitive_iterator_t(); | ||
} | ||
|
||
private: | ||
int8_t m_it_type = -1; // we assume that type will never change once initialized | ||
}; | ||
|
||
/*! | ||
@brief Implementation of internal_iterator for trivially destructible types | ||
*/ | ||
template<typename BasicJsonType> struct internal_iterator | ||
template<class BasicJsonType> | ||
class internal_iterator_impl<BasicJsonType, true> : public internal_iterator_base<BasicJsonType> | ||
{ | ||
/// iterator for JSON objects | ||
typename BasicJsonType::object_t::iterator object_iterator {}; | ||
/// iterator for JSON arrays | ||
typename BasicJsonType::array_t::iterator array_iterator {}; | ||
/// generic iterator for all other types | ||
primitive_iterator_t primitive_iterator {}; | ||
public: | ||
using ObjectIterator = typename BasicJsonType::object_t::iterator; | ||
using ArrayIterator = typename BasicJsonType::array_t::iterator; | ||
|
||
internal_iterator_impl() noexcept = default; | ||
|
||
void init_object_iterator() | ||
{ | ||
new (reinterpret_cast<ObjectIterator*>(&this->m_data)) ObjectIterator(); | ||
} | ||
|
||
template<class ObjIt> | ||
void set_object_iterator(ObjIt&& it) | ||
{ | ||
*reinterpret_cast<ObjectIterator*>(&this->m_data) = std::forward<ObjIt>(it); | ||
} | ||
|
||
void init_array_iterator() | ||
{ | ||
new (reinterpret_cast<ArrayIterator*>(&this->m_data)) ArrayIterator(); | ||
} | ||
|
||
template<class ArrIt> | ||
void set_array_iterator(ArrIt&& it) | ||
{ | ||
*reinterpret_cast<ArrayIterator*>(&this->m_data) = std::forward<ArrIt>(it); | ||
} | ||
|
||
void init_primitive_iterator() | ||
{ | ||
new (reinterpret_cast<primitive_iterator_t*>(&this->m_data)) primitive_iterator_t(); | ||
} | ||
}; | ||
|
||
/*! | ||
@brief an iterator value | ||
*/ | ||
template<typename BasicJsonType> | ||
using internal_iterator = internal_iterator_impl < BasicJsonType, std::is_trivially_destructible<typename BasicJsonType::object_t::iterator>::value && std::is_trivially_destructible<typename BasicJsonType::array_t::iterator>::value && std::is_trivially_destructible<primitive_iterator_t>::value >; | ||
|
||
} // namespace detail | ||
} // namespace nlohmann | ||
|
Oops, something went wrong.