MongoDB C++ Driver mongocxx-3.0.0
Loading...
Searching...
No Matches
stack.hpp
1// Copyright 2014 MongoDB Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <list>
18#include <memory>
19#include <type_traits>
20
21#include <bsoncxx/config/private/prelude.hpp>
22
23namespace bsoncxx {
24BSONCXX_INLINE_NAMESPACE_BEGIN
25
26template <typename T, std::size_t size>
27class stack {
28 public:
29 stack() : _bucket_index(0), _bucket_size(size), _is_empty(true) {
30 }
31
32 ~stack() {
33 while (!empty()) {
34 pop_back();
35 }
36
37 while (!_buckets.empty()) {
38 operator delete(_buckets.back());
39 _buckets.pop_back();
40 }
41 }
42
43 bool empty() const {
44 return _is_empty;
45 }
46
47 T &back() {
48 return *(_get_ptr());
49 }
50
51 template <typename... Args>
52 void emplace_back(Args &&... args) {
53 if (_is_empty) {
54 _is_empty = false;
55 } else {
56 _inc();
57 }
58
59 new (_get_ptr()) T(std::forward<Args>(args)...);
60 }
61
62 void pop_back() {
63 _dec();
64 }
65
66 void unsafe_reset() {
67 _bucket_index = 0;
68 if (!_buckets.empty()) {
69 _bucket_iter = _buckets.begin();
70 }
71 _is_empty = true;
72 }
73
74 private:
75 typename std::aligned_storage<sizeof(T), alignof(T)>::type _object_memory[size];
76
77 std::list<T *> _buckets;
78
79 typename std::list<T *>::iterator _bucket_iter;
80
81 int _bucket_index;
82 int _bucket_size;
83 bool _is_empty;
84
85 T *_get_ptr() {
86 if (_bucket_size == size) {
87 return reinterpret_cast<T *>(_object_memory) + _bucket_index;
88 } else {
89 return *(_bucket_iter) + _bucket_index;
90 }
91 }
92
93 void _inc() {
94 if (_bucket_index == _bucket_size - 1) {
95 _bucket_index = 0;
96 _bucket_size *= 2;
97
98 if (_buckets.empty()) {
99 // first pass at needing dynamic memory
100 _buckets.emplace_back(
101 reinterpret_cast<T *>(operator new(sizeof(T) * _bucket_size)));
102
103 _bucket_iter = _buckets.begin();
104 } else if (_bucket_size != size * 2) {
105 // we're _not_ transitioning from stack to heap
106 auto tmp_iter = _bucket_iter;
107
108 if (++tmp_iter == _buckets.end()) {
109 _buckets.emplace_back(
110 reinterpret_cast<T *>(operator new(sizeof(T) * _bucket_size)));
111 }
112 ++_bucket_iter;
113 }
114 } else {
115 ++_bucket_index;
116 }
117 }
118
119 void _dec() {
120 _get_ptr()->~T();
121
122 if (_bucket_index == 0) {
123 if (_bucket_size == size) {
124 /* we're already in object memory */
125 _is_empty = true;
126 } else {
127 /* we're on the linked list */
128 _bucket_size /= 2;
129 _bucket_index = _bucket_size - 1;
130
131 if (_bucket_iter != _buckets.begin()) {
132 --_bucket_iter;
133 }
134 }
135 } else {
136 --_bucket_index;
137 }
138 }
139};
140
141BSONCXX_INLINE_NAMESPACE_END
142} // namespace bsoncxx
143
144#include <bsoncxx/config/private/postlude.hpp>
Definition stack.hpp:27