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