30 template <
size_t _PageSize>
38 static size_t page_size(){
return _PageSize; }
52 static size_t page_size(){
return xtd::memory::page_size(); }
56 template <
size_t _PageSize,
size_t _CacheSize>
class lru_cache;
58 template <
size_t _PageSize>
60 template <
size_t,
size_t>
friend class lru_cache;
69 return _File.template get<data_page<_PageSize>>(pagenum);
73 template <
size_t _PageSize,
size_t _CacheSize>
74 class lru_cache :
public xtd::lru_cache<size_t, typename data_page<_PageSize>::pointer, _CacheSize, page_loader<_PageSize> >{
79 static const size_t cache_size = _CacheSize;
82 typename data_page<_PageSize>::pointer append(
size_t & newpage){
83 if (_super_t::size() >= cache_size){
86 _super_t::push_front(std::make_pair(newpage, _loader._File.template append<data_page<_PageSize>>(newpage)));
87 return _super_t::front().second;
94 template <
size_t _PageSize>
98 static const page_type type = page_type::file_header_page;
109 template <
typename _KeyT,
typename _ValueT,
size_t _PageSize>
113 using key_type = _KeyT;
114 using value_type = _ValueT;
116 static const page_type type = page_type::leaf_page;
129 static inline size_t records_per_page(){
133 static inline size_t records_per_page(){
134 static size_t iRet = (_super_t::page_size() -
sizeof(page_header) -
sizeof(
data_page<_PageSize>)) /
sizeof(record);
139 bool insert(
const key_type& key,
const value_type& value){
140 _records[_page_header._count]._key = key;
141 _records[_page_header._count]._value = value;
142 std::sort(&_records[0], &_records[_page_header._count], [](
const record& lhs,
const record& rhs)->bool{
return lhs._key < rhs._key; });
143 _page_header._count++;
147 template <
typename _CacheT>
148 void split(_CacheT& oCache,
size_t left_page_idx, key_type& left_page_key,
size_t& right_page_idx){
149 auto oNewPage = static_page_cast<leaf>(oCache[right_page_idx]);
150 D_(
const leaf * pNewPage = oNewPage.get());
151 left_page_key = _records[records_per_page() / 2]._key;
152 for (
size_t i = 1+(records_per_page() / 2); i < records_per_page(); ++i, ++oNewPage->_page_header._count, --_page_header._count){
153 oNewPage->_records[oNewPage->_page_header._count] = _records[i];
155 _page_header._next_page = right_page_idx;
156 oNewPage->_page_header._prev_page = left_page_idx;
159 page_header _page_header;
168 template <
typename _KeyT,
typename _ValueT,
size_t _PageSize>
174 using key_type = _KeyT;
175 using value_type = _ValueT;
176 static const page_type type = page_type::branch_page;
189 static inline size_t records_per_page(){
193 static inline size_t records_per_page(){
194 static size_t iRet = ((_super_t::page_size() -
sizeof(page_header) -
sizeof(
data_page<_PageSize>)) /
sizeof(record));
199 template <
typename _CacheT>
200 inline bool insert(_CacheT& oCache,
const key_type& key,
const value_type& value){
201 typename _super_t::pointer oPage;
203 TODO(
"binary search instead of full scan")
204 for (
size_t i = 0; i < _page_header._count; ++i){
205 if (key <= _records[i]._key){
206 oPage = static_page_cast<_super_t>(oCache[_records[i]._left]);
207 if (page_type::leaf_page == oPage->_page_type){
208 auto oLeaf = xtd::static_page_cast<leaf_t>(oPage);
209 D_(
const leaf_t * pLeaf = oLeaf.get());
210 if (oLeaf->_page_header._count >= leaf_t::records_per_page()){
211 _records[_page_header._count]._left = _records[i]._left;
212 oLeaf->split(oCache, _records[i]._left, _records[_page_header._count]._key, _records[i]._left);
213 std::sort(&_records[0], &_records[_page_header._count], [](
const record& lhs,
const record& rhs){
return lhs._key < rhs._key; });
214 _page_header._count++;
217 return oLeaf->insert(key, value);
219 auto oBranch = xtd::static_page_cast<branch>(oPage);
220 D_(
const branch * pBranch = oBranch.get());
221 if (oBranch->_page_header._count >= branch::records_per_page()){
222 _records[_page_header._count] = _records[i];
223 oBranch->split(oCache, _records[_page_header._count]._key, _records[i]._left);
224 std::sort(&_records[0], &_records[_page_header._count], [](
const record& lhs,
const record& rhs){
return lhs._key < rhs._key; });
225 _page_header._count++;
228 return oBranch->insert(oCache, key, value);
232 oPage = static_page_cast<_super_t>(oCache[_page_header._right]);
233 if (page_type::leaf_page == oPage->_page_type){
234 auto oLeaf = xtd::static_page_cast<leaf_t>(oPage);
235 D_(
const leaf_t * pLeaf = oLeaf.get());
236 if (oLeaf->_page_header._count >= leaf_t::records_per_page()){
237 _records[_page_header._count]._left = _page_header._right;
238 oLeaf->split(oCache, _page_header._right, _records[_page_header._count]._key, _page_header._right);
239 std::sort(&_records[0], &_records[_page_header._count], [](
const record& lhs,
const record& rhs){
return lhs._key < rhs._key; });
240 _page_header._count++;
243 return oLeaf->insert(key, value);
245 auto oBranch = xtd::static_page_cast<branch>(oPage);
246 D_(
const branch * pBranch = oBranch.get());
247 if (oBranch->_page_header._count < branch::records_per_page()){
248 _records[_page_header._count]._left = _page_header._right;
249 oBranch->split(oCache, _records[_page_header._count]._key, _page_header._right);
250 std::sort(&_records[0], &_records[_page_header._count], [](
const record& lhs,
const record& rhs){
return lhs._key < rhs._key; });
251 _page_header._count++;
254 return oBranch->insert(oCache, key, value);
259 template <
typename _CacheT>
260 inline void split(_CacheT& oCache, key_type& left_page_key,
size_t & right_page_idx){
261 auto oNewPage = static_page_cast<branch>(oCache[right_page_idx]);
262 D_(
const branch * pNewPage = oNewPage.get());
263 TODO(
"convert to memcpy")
264 for (
size_t i = 1+records_per_page() / 2; i < records_per_page(); ++i, ++oNewPage->_page_header._count, --_page_header._count){
265 oNewPage->_records[oNewPage->_page_header._count] = _records[i];
267 left_page_key = _records[records_per_page() / 2]._key;
279 template <
typename _KeyT,
typename _ValueT,
size_t _PageSize = -1,
size_t _CacheSize = 20>
class btree{
281 using key_type = _KeyT;
282 using value_type = _ValueT;
290 using page_type = _::btree::page_type;
303 bool insert(
const key_type& key,
const value_type& value){
305 if (0 == _file_header->_root_page){
306 auto oLeaf = static_page_cast<
leaf_t>(_cache.append(_file_header->_root_page));
307 D_(
const leaf_t * pLeaf = oLeaf.get());
308 if (oLeaf->insert(key, value)){
309 _file_header->_count++;
315 auto oRoot = static_page_cast<
data_page_t>(_cache[_file_header->_root_page]);
317 if (page_type::branch_page == oRoot->_page_type){
320 auto oBranch = xtd::static_page_cast<
branch_t>(oRoot);
321 D_(
const branch_t * pBranch = oBranch.get());
322 if (oBranch->_page_header._count >= branch_t::records_per_page()){
324 auto oNewRoot = static_page_cast<
branch_t>(_cache[iNewRoot]);
325 oBranch->split(_cache, oNewRoot->_records[0]._key, oNewRoot->_page_header._right);
326 oNewRoot->_records[0]._left = _file_header->_root_page;
327 oNewRoot->_page_header._count = 1;
328 _file_header->_root_page = iNewRoot;
329 oBranch = std::move(oNewRoot);
332 if (oBranch->insert(_cache, key, value)){
333 _file_header->_count++;
339 auto oLeaf = xtd::static_page_cast<
leaf_t>(oRoot);
340 D_(
const leaf_t * pLeaf = oLeaf.get());
342 if (oLeaf->_page_header._count < leaf_t::records_per_page()){
343 if (oLeaf->insert(key, value)){
344 _file_header->_count++;
350 auto iOldRootIdx = _file_header->_root_page;
351 auto oNewRoot = static_page_cast<
branch_t>(_cache[_file_header->_root_page]);
352 oNewRoot->_records[0]._left = iOldRootIdx;
353 oLeaf->split(_cache, iOldRootIdx, oNewRoot->_records[0]._key, oNewRoot->_page_header._right);
354 oNewRoot->_page_header._count = 1;
355 if (oNewRoot->insert(_cache, key, value)){
356 _file_header->_count++;
B-Tree key-value container.
host, target and build configurations and settings Various components are purpose built for specific ...
handle necessary filesystem and path functionality until C++17 is finalized
base class of btree pages
leaf page contains all the keys and values
branch page contains keys and indexes to more branch or leaf pages
bool insert(const key_type &key, const value_type &value)
insert a value in the container