stack.hpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/json
  8. //
  9. #ifndef BOOST_JSON_DETAIL_IMPL_STACK_HPP
  10. #define BOOST_JSON_DETAIL_IMPL_STACK_HPP
  11. #include <boost/core/detail/static_assert.hpp>
  12. #include <memory>
  13. namespace boost {
  14. namespace json {
  15. namespace detail {
  16. template<>
  17. struct stack::non_trivial<void>
  18. {
  19. using relocate_t = non_trivial* (*) (non_trivial*, void*);
  20. relocate_t rel;
  21. non_trivial* next;
  22. std::size_t offset;
  23. BOOST_JSON_DECL
  24. non_trivial<>*
  25. destroy() noexcept;
  26. BOOST_JSON_DECL
  27. non_trivial*
  28. relocate(void* dst) noexcept;
  29. protected:
  30. ~non_trivial() = default;
  31. };
  32. template< class T >
  33. struct stack::non_trivial
  34. : stack::non_trivial<void>
  35. {
  36. T obj;
  37. explicit
  38. non_trivial(T t, non_trivial<>* next, std::size_t offset)
  39. : non_trivial<void>{relocate, next, offset}, obj( std::move(t) )
  40. {}
  41. static
  42. non_trivial<>*
  43. relocate(non_trivial<>* src, void* dest) noexcept
  44. {
  45. non_trivial* self = static_cast<non_trivial*>(src);
  46. non_trivial<>* result = nullptr;
  47. if( dest )
  48. result = ::new(dest) non_trivial( std::move(*self) );
  49. self->~non_trivial();
  50. return result;
  51. }
  52. };
  53. template<class T>
  54. void
  55. stack::
  56. push_unchecked(T const& t)
  57. {
  58. constexpr std::size_t n = sizeof(T);
  59. BOOST_CORE_STATIC_ASSERT( is_trivially_copy_assignable<T>::value );
  60. BOOST_ASSERT( n <= cap_ - size_ );
  61. std::memcpy( base_ + size_, &t, n );
  62. size_ += n;
  63. }
  64. template<class T>
  65. void
  66. stack::
  67. peek(T& t)
  68. {
  69. constexpr std::size_t n = sizeof(T);
  70. BOOST_CORE_STATIC_ASSERT( is_trivially_copy_assignable<T>::value );
  71. BOOST_ASSERT( size_ >= n );
  72. std::memcpy( &t, base_ + size_ - n, n );
  73. }
  74. //--------------------------------------
  75. // trivial
  76. template<class T>
  77. void
  78. stack::
  79. push(T const& t, std::true_type)
  80. {
  81. if( sizeof(T) > cap_ - size_ )
  82. reserve_impl( sizeof(T) + size_ );
  83. push_unchecked(t);
  84. }
  85. // non-trivial
  86. template<class T>
  87. void
  88. stack::
  89. push(T&& t, std::false_type)
  90. {
  91. BOOST_CORE_STATIC_ASSERT( ! is_trivially_copy_assignable<T>::value );
  92. using Holder = non_trivial< remove_cvref<T> >;
  93. constexpr std::size_t size = sizeof(Holder);
  94. constexpr std::size_t alignment = alignof(Holder);
  95. void* ptr;
  96. std::size_t offset;
  97. do
  98. {
  99. std::size_t space = cap_ - size_;
  100. unsigned char* buf = base_ + size_;
  101. ptr = buf;
  102. if( std::align(alignment, size, ptr, space) )
  103. {
  104. offset = (reinterpret_cast<unsigned char*>(ptr) - buf) + size;
  105. break;
  106. }
  107. reserve_impl(size_ + size + alignment - 1);
  108. }
  109. while(true);
  110. BOOST_ASSERT(
  111. (reinterpret_cast<unsigned char*>(ptr) + size - offset) ==
  112. (base_ + size_) );
  113. head_ = ::new(ptr) Holder( static_cast<T&&>(t), head_, offset );
  114. size_ += offset;
  115. }
  116. // trivial
  117. template<class T>
  118. void
  119. stack::
  120. pop(T& t, std::true_type)
  121. {
  122. BOOST_ASSERT( size_ >= sizeof(T) );
  123. peek(t);
  124. size_ -= sizeof(T);
  125. }
  126. // non-trivial
  127. template<class T>
  128. void
  129. stack::
  130. pop(T& t, std::false_type)
  131. {
  132. auto next = head_->next;
  133. auto offset = head_->offset;
  134. using U = remove_cvref<T>;
  135. using Holder = non_trivial<U>;
  136. auto const head = static_cast<Holder*>(head_);
  137. t = std::move( head->obj );
  138. head->~Holder();
  139. head_ = next;
  140. size_ -= offset;
  141. }
  142. } // detail
  143. } // json
  144. } // boost
  145. #endif