Skip to content

Commit

Permalink
Optimize copy / assignment and size of json iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
sjanel committed Apr 24, 2022
1 parent 1a90c94 commit 9878d78
Show file tree
Hide file tree
Showing 8 changed files with 1,256 additions and 989 deletions.
186 changes: 176 additions & 10 deletions include/nlohmann/detail/iterators/internal_iterator.hpp
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

Loading

0 comments on commit 9878d78

Please sign in to comment.