Line data Source code
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 :
10 : #ifndef BOOST_JSON_DETAIL_IMPL_STACK_HPP
11 : #define BOOST_JSON_DETAIL_IMPL_STACK_HPP
12 :
13 : #include <boost/align/align.hpp>
14 : #include <boost/static_assert.hpp>
15 :
16 : namespace boost {
17 : namespace json {
18 : namespace detail {
19 :
20 : template<>
21 : struct stack::non_trivial<void>
22 : {
23 : using relocate_t = non_trivial* (*) (non_trivial*, void*);
24 :
25 : relocate_t rel;
26 : non_trivial* next;
27 : std::size_t offset;
28 :
29 : BOOST_JSON_DECL
30 : non_trivial<>*
31 : destroy() noexcept;
32 :
33 : BOOST_JSON_DECL
34 : non_trivial*
35 : relocate(void* dst) noexcept;
36 :
37 : protected:
38 : ~non_trivial() = default;
39 : };
40 :
41 : template< class T >
42 : struct stack::non_trivial
43 : : stack::non_trivial<void>
44 : {
45 : T obj;
46 :
47 : explicit
48 4 : non_trivial(T t, non_trivial<>* next, std::size_t offset)
49 4 : : non_trivial<void>{relocate, next, offset}, obj( std::move(t) )
50 4 : {}
51 :
52 : static
53 : non_trivial<>*
54 4 : relocate(non_trivial<>* src, void* dest) noexcept
55 : {
56 4 : non_trivial* self = static_cast<non_trivial*>(src);
57 4 : non_trivial<>* result = nullptr;
58 4 : if( dest )
59 3 : result = ::new(dest) non_trivial( std::move(*self) );
60 4 : self->~non_trivial();
61 4 : return result;
62 : }
63 : };
64 :
65 : template<class T>
66 : void
67 332671 : stack::
68 : push_unchecked(T const& t)
69 : {
70 332671 : constexpr std::size_t n = sizeof(T);
71 : BOOST_STATIC_ASSERT( is_trivially_copy_assignable<T>::value );
72 332671 : BOOST_ASSERT( n <= cap_ - size_ );
73 332671 : std::memcpy( base_ + size_, &t, n );
74 332671 : size_ += n;
75 332671 : }
76 :
77 : template<class T>
78 : void
79 796778 : stack::
80 : peek(T& t)
81 : {
82 796778 : constexpr std::size_t n = sizeof(T);
83 : BOOST_STATIC_ASSERT( is_trivially_copy_assignable<T>::value );
84 796778 : BOOST_ASSERT( size_ >= n );
85 796778 : std::memcpy( &t, base_ + size_ - n, n );
86 796778 : }
87 :
88 : //--------------------------------------
89 :
90 : // trivial
91 : template<class T>
92 : void
93 47892 : stack::
94 : push(T const& t, std::true_type)
95 : {
96 47892 : if( sizeof(T) > cap_ - size_ )
97 8953 : reserve_impl( sizeof(T) + size_ );
98 47890 : push_unchecked(t);
99 47890 : }
100 :
101 : // non-trivial
102 : template<class T>
103 : void
104 4 : stack::
105 : push(T&& t, std::false_type)
106 : {
107 : BOOST_STATIC_ASSERT( ! is_trivially_copy_assignable<T>::value );
108 :
109 : using Holder = non_trivial< remove_cvref<T> >;
110 4 : constexpr std::size_t size = sizeof(Holder);
111 4 : constexpr std::size_t alignment = alignof(Holder);
112 :
113 : void* ptr;
114 : std::size_t offset;
115 : do
116 : {
117 7 : std::size_t space = cap_ - size_;
118 7 : unsigned char* buf = base_ + size_;
119 7 : ptr = buf;
120 7 : if( alignment::align(alignment, size, ptr, space) )
121 : {
122 4 : offset = (reinterpret_cast<unsigned char*>(ptr) - buf) + size;
123 4 : break;
124 : }
125 :
126 3 : reserve_impl(size_ + size + alignment - 1);
127 3 : }
128 : while(true);
129 4 : BOOST_ASSERT(
130 : (reinterpret_cast<unsigned char*>(ptr) + size - offset) ==
131 : (base_ + size_) );
132 :
133 4 : head_ = ::new(ptr) Holder( static_cast<T&&>(t), head_, offset );
134 4 : size_ += offset;
135 4 : }
136 :
137 : // trivial
138 : template<class T>
139 : void
140 329190 : stack::
141 : pop(T& t, std::true_type)
142 : {
143 329190 : BOOST_ASSERT( size_ >= sizeof(T) );
144 329190 : peek(t);
145 329190 : size_ -= sizeof(T);
146 329190 : }
147 :
148 : // non-trivial
149 : template<class T>
150 : void
151 3 : stack::
152 : pop(T& t, std::false_type)
153 : {
154 3 : auto next = head_->next;
155 3 : auto offset = head_->offset;
156 :
157 : using U = remove_cvref<T>;
158 : using Holder = non_trivial<U>;
159 3 : auto const head = static_cast<Holder*>(head_);
160 :
161 3 : t = std::move( head->obj );
162 3 : head->~Holder();
163 :
164 3 : head_ = next;
165 3 : size_ -= offset;
166 3 : }
167 :
168 : } // detail
169 : } // json
170 : } // boost
171 :
172 : #endif
|