update credits
[LibreOffice.git] / store / source / stortree.cxx
blob149982438f4ebc6961e38001bfb7d347e2284152
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "stortree.hxx"
23 #include "sal/types.h"
24 #include "osl/diagnose.h"
26 #include "store/types.h"
28 #include "storbase.hxx"
29 #include "storbios.hxx"
31 using namespace store;
33 /*========================================================================
35 * OStoreBTreeNodeData implementation.
37 *======================================================================*/
39 * OStoreBTreeNodeData.
41 OStoreBTreeNodeData::OStoreBTreeNodeData (sal_uInt16 nPageSize)
42 : OStorePageData (nPageSize)
44 base::m_aGuard.m_nMagic = store::htonl(self::theTypeId);
45 base::m_aDescr.m_nUsed = store::htons(self::thePageSize); // usageCount(0)
46 self::m_aGuard.m_nMagic = store::htonl(0); // depth(0)
48 sal_uInt16 const n = capacityCount();
49 T const t;
51 for (sal_uInt16 i = 1; i < n; i++)
52 m_pData[i] = t;
56 * find.
58 sal_uInt16 OStoreBTreeNodeData::find (const T& t) const
60 register sal_Int32 l = 0;
61 register sal_Int32 r = usageCount() - 1;
63 while (l < r)
65 register sal_Int32 const m = ((l + r) >> 1);
67 if (t.m_aKey == m_pData[m].m_aKey)
68 return ((sal_uInt16)(m));
69 if (t.m_aKey < m_pData[m].m_aKey)
70 r = m - 1;
71 else
72 l = m + 1;
75 sal_uInt16 const k = ((sal_uInt16)(r));
76 if ((k < capacityCount()) && (t.m_aKey < m_pData[k].m_aKey))
77 return(k - 1);
78 else
79 return(k);
83 * insert.
85 void OStoreBTreeNodeData::insert (sal_uInt16 i, const T& t)
87 sal_uInt16 const n = usageCount();
88 sal_uInt16 const m = capacityCount();
89 if ((n < m) && (i < m))
91 // shift right.
92 memmove (&(m_pData[i + 1]), &(m_pData[i]), (n - i) * sizeof(T));
94 // insert.
95 m_pData[i] = t;
96 usageCount (n + 1);
101 * remove.
103 void OStoreBTreeNodeData::remove (sal_uInt16 i)
105 sal_uInt16 const n = usageCount();
106 if (i < n)
108 // shift left.
109 memmove (&(m_pData[i]), &(m_pData[i + 1]), (n - i - 1) * sizeof(T));
111 // truncate.
112 m_pData[n - 1] = T();
113 usageCount (n - 1);
118 * split (left half copied from right half of left page).
120 void OStoreBTreeNodeData::split (const self& rPageL)
122 sal_uInt16 const h = capacityCount() / 2;
123 memcpy (&(m_pData[0]), &(rPageL.m_pData[h]), h * sizeof(T));
124 truncate (h);
128 * truncate.
130 void OStoreBTreeNodeData::truncate (sal_uInt16 n)
132 sal_uInt16 const m = capacityCount();
133 T const t;
135 for (sal_uInt16 i = n; i < m; i++)
136 m_pData[i] = t;
137 usageCount (n);
140 /*========================================================================
142 * OStoreBTreeNodeObject implementation.
144 *======================================================================*/
146 * guard.
148 storeError OStoreBTreeNodeObject::guard (sal_uInt32 nAddr)
150 return PageHolderObject< page >::guard (m_xPage, nAddr);
154 * verify.
156 storeError OStoreBTreeNodeObject::verify (sal_uInt32 nAddr) const
158 return PageHolderObject< page >::verify (m_xPage, nAddr);
162 * split.
164 storeError OStoreBTreeNodeObject::split (
165 sal_uInt16 nIndexL,
166 PageHolderObject< page > & rxPageL,
167 OStorePageBIOS & rBIOS)
169 PageHolderObject< page > xPage (m_xPage);
170 if (!xPage.is())
171 return store_E_InvalidAccess;
173 // Check left page usage.
174 if (!rxPageL.is())
175 return store_E_InvalidAccess;
176 if (!rxPageL->querySplit())
177 return store_E_None;
179 // Construct right page.
180 PageHolderObject< page > xPageR;
181 if (!xPageR.construct (rBIOS.allocator()))
182 return store_E_OutOfMemory;
184 // Split right page off left page.
185 xPageR->split (*rxPageL);
186 xPageR->depth (rxPageL->depth());
188 // Allocate right page.
189 self aNodeR (xPageR.get());
190 storeError eErrCode = rBIOS.allocate (aNodeR);
191 if (eErrCode != store_E_None)
192 return eErrCode;
194 // Truncate left page.
195 rxPageL->truncate (rxPageL->capacityCount() / 2);
197 // Save left page.
198 self aNodeL (rxPageL.get());
199 eErrCode = rBIOS.saveObjectAt (aNodeL, aNodeL.location());
200 if (eErrCode != store_E_None)
201 return eErrCode;
203 // Insert right page.
204 OStorePageLink aLink (xPageR->location());
205 xPage->insert (nIndexL + 1, T(xPageR->m_pData[0].m_aKey, aLink));
207 // Save this page and leave.
208 return rBIOS.saveObjectAt (*this, location());
212 * remove (down to leaf node, recursive).
214 storeError OStoreBTreeNodeObject::remove (
215 sal_uInt16 nIndexL,
216 OStoreBTreeEntry & rEntryL,
217 OStorePageBIOS & rBIOS)
219 PageHolderObject< page > xImpl (m_xPage);
220 page & rPage = (*xImpl);
222 // Check depth.
223 storeError eErrCode = store_E_None;
224 if (rPage.depth())
226 // Check link entry.
227 T const aEntryL (rPage.m_pData[nIndexL]);
228 if (!(rEntryL.compare (aEntryL) == T::COMPARE_EQUAL))
229 return store_E_InvalidAccess;
231 // Load link node.
232 self aNodeL;
233 eErrCode = rBIOS.loadObjectAt (aNodeL, aEntryL.m_aLink.location());
234 if (eErrCode != store_E_None)
235 return eErrCode;
237 // Recurse: remove from link node.
238 eErrCode = aNodeL.remove (0, rEntryL, rBIOS);
239 if (eErrCode != store_E_None)
240 return eErrCode;
242 // Check resulting link node usage.
243 PageHolderObject< page > xPageL (aNodeL.get());
244 if (xPageL->usageCount() == 0)
246 // Free empty link node.
247 eErrCode = rBIOS.free (xPageL->location());
248 if (eErrCode != store_E_None)
249 return eErrCode;
251 // Remove index.
252 rPage.remove (nIndexL);
253 touch();
255 else
258 // Relink.
259 rPage.m_pData[nIndexL].m_aKey = xPageL->m_pData[0].m_aKey;
260 touch();
263 else
265 // Check leaf entry.
266 if (!(rEntryL.compare (rPage.m_pData[nIndexL]) == T::COMPARE_EQUAL))
267 return store_E_NotExists;
269 // Save leaf entry.
270 rEntryL = rPage.m_pData[nIndexL];
272 // Remove leaf index.
273 rPage.remove (nIndexL);
274 touch();
277 // Check for modified node.
278 if (dirty())
280 // Save this page.
281 eErrCode = rBIOS.saveObjectAt (*this, location());
284 // Done.
285 return eErrCode;
288 /*========================================================================
290 * OStoreBTreeRootObject implementation.
292 *======================================================================*/
294 * testInvariant.
295 * Precond: root node page loaded.
297 bool OStoreBTreeRootObject::testInvariant (char const * message)
299 OSL_PRECOND(m_xPage.get() != 0, "OStoreBTreeRootObject::testInvariant(): Null pointer");
300 bool result = ((m_xPage->location() - m_xPage->size()) == 0);
301 OSL_POSTCOND(result, message); (void) message;
302 return result;
306 * loadOrCreate.
308 storeError OStoreBTreeRootObject::loadOrCreate (
309 sal_uInt32 nAddr,
310 OStorePageBIOS & rBIOS)
312 storeError eErrCode = rBIOS.loadObjectAt (*this, nAddr);
313 if (eErrCode != store_E_NotExists)
314 return eErrCode;
316 eErrCode = construct<page>(rBIOS.allocator());
317 if (eErrCode != store_E_None)
318 return eErrCode;
320 eErrCode = rBIOS.allocate (*this);
321 if (eErrCode != store_E_None)
322 return eErrCode;
324 // Notify caller of the creation.
325 (void) testInvariant("OStoreBTreeRootObject::loadOrCreate(): leave");
326 return store_E_Pending;
330 * change.
332 storeError OStoreBTreeRootObject::change (
333 PageHolderObject< page > & rxPageL,
334 OStorePageBIOS & rBIOS)
336 PageHolderObject< page > xPage (m_xPage);
337 (void) testInvariant("OStoreBTreeRootObject::change(): enter");
339 // Save root location.
340 sal_uInt32 const nRootAddr = xPage->location();
342 // Construct new root.
343 if (!rxPageL.construct (rBIOS.allocator()))
344 return store_E_OutOfMemory;
346 // Save this as prev root.
347 storeError eErrCode = rBIOS.allocate (*this);
348 if (eErrCode != store_E_None)
349 return store_E_OutOfMemory;
351 // Setup new root.
352 rxPageL->depth (xPage->depth() + 1);
353 rxPageL->m_pData[0] = xPage->m_pData[0];
354 rxPageL->m_pData[0].m_aLink = xPage->location();
355 rxPageL->usageCount(1);
357 // Change root.
358 rxPageL.swap (xPage);
360 PageHolder tmp (xPage.get());
361 tmp.swap (m_xPage);
364 // Save this as new root and finish.
365 eErrCode = rBIOS.saveObjectAt (*this, nRootAddr);
366 (void) testInvariant("OStoreBTreeRootObject::change(): leave");
367 return eErrCode;
371 * find_lookup (w/o split()).
372 * Precond: root node page loaded.
374 storeError OStoreBTreeRootObject::find_lookup (
375 OStoreBTreeNodeObject & rNode, // [out]
376 sal_uInt16 & rIndex, // [out]
377 OStorePageKey const & rKey,
378 OStorePageBIOS & rBIOS)
380 // Init node w/ root page.
381 (void) testInvariant("OStoreBTreeRootObject::find_lookup(): enter");
383 PageHolder tmp (m_xPage);
384 tmp.swap (rNode.get());
387 // Setup BTree entry.
388 T const entry (rKey);
390 // Check current page.
391 PageHolderObject< page > xPage (rNode.get());
392 for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >())
394 // Find next page.
395 page const & rPage = (*xPage);
396 sal_uInt16 const i = rPage.find(entry);
397 sal_uInt16 const n = rPage.usageCount();
398 if (!(i < n))
400 // Path to entry not exists (Must not happen(?)).
401 return store_E_NotExists;
404 // Check address.
405 sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location();
406 if (nAddr == STORE_PAGE_NULL)
408 // Path to entry not exists (Must not happen(?)).
409 return store_E_NotExists;
412 // Load next page.
413 storeError eErrCode = rBIOS.loadObjectAt (rNode, nAddr);
414 if (eErrCode != store_E_None)
415 return eErrCode;
418 // Find index.
419 page const & rPage = (*xPage);
420 rIndex = rPage.find(entry);
421 if (!(rIndex < rPage.usageCount()))
422 return store_E_NotExists;
424 // Compare entry.
425 T::CompareResult eResult = entry.compare(rPage.m_pData[rIndex]);
426 OSL_POSTCOND(eResult != T::COMPARE_LESS, "store::BTreeRoot::find_lookup(): sort error");
427 if (eResult == T::COMPARE_LESS)
428 return store_E_Unknown;
430 // Greater or Equal.
431 (void) testInvariant("OStoreBTreeRootObject::find_lookup(): leave");
432 return store_E_None;
436 * find_insert (possibly with split()).
437 * Precond: root node page loaded.
439 storeError OStoreBTreeRootObject::find_insert (
440 OStoreBTreeNodeObject & rNode, // [out]
441 sal_uInt16 & rIndex, // [out]
442 OStorePageKey const & rKey,
443 OStorePageBIOS & rBIOS)
445 (void) testInvariant("OStoreBTreeRootObject::find_insert(): enter");
447 // Check for RootNode split.
448 PageHolderObject< page > xRoot (m_xPage);
449 if (xRoot->querySplit())
451 PageHolderObject< page > xPageL;
453 // Change root.
454 storeError eErrCode = change (xPageL, rBIOS);
455 if (eErrCode != store_E_None)
456 return eErrCode;
458 // Split left page (prev root).
459 eErrCode = split (0, xPageL, rBIOS);
460 if (eErrCode != store_E_None)
461 return eErrCode;
464 // Init node w/ root page.
466 PageHolder tmp (m_xPage);
467 tmp.swap (rNode.get());
470 // Setup BTree entry.
471 T const entry (rKey);
473 // Check current Page.
474 PageHolderObject< page > xPage (rNode.get());
475 for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >())
477 // Find next page.
478 page const & rPage = (*xPage);
479 sal_uInt16 const i = rPage.find (entry);
480 sal_uInt16 const n = rPage.usageCount();
481 if (!(i < n))
483 // Path to entry not exists (Must not happen(?)).
484 return store_E_NotExists;
487 // Check address.
488 sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location();
489 if (nAddr == STORE_PAGE_NULL)
491 // Path to entry not exists (Must not happen(?)).
492 return store_E_NotExists;
495 // Load next page.
496 OStoreBTreeNodeObject aNext;
497 storeError eErrCode = rBIOS.loadObjectAt (aNext, nAddr);
498 if (eErrCode != store_E_None)
499 return eErrCode;
501 // Check for next node split.
502 PageHolderObject< page > xNext (aNext.get());
503 if (xNext->querySplit())
505 // Split next node.
506 eErrCode = rNode.split (i, xNext, rBIOS);
507 if (eErrCode != store_E_None)
508 return eErrCode;
510 // Restart.
511 continue;
514 // Let next page be current.
515 PageHolder tmp (aNext.get());
516 tmp.swap (rNode.get());
519 // Find index.
520 page const & rPage = (*xPage);
521 rIndex = rPage.find(entry);
522 if (rIndex < rPage.usageCount())
524 // Compare entry.
525 T::CompareResult result = entry.compare (rPage.m_pData[rIndex]);
526 OSL_POSTCOND(result != T::COMPARE_LESS, "store::BTreeRoot::find_insert(): sort error");
527 if (result == T::COMPARE_LESS)
528 return store_E_Unknown;
530 if (result == T::COMPARE_EQUAL)
531 return store_E_AlreadyExists;
534 // Greater or not (yet) existing.
535 (void) testInvariant("OStoreBTreeRootObject::find_insert(): leave");
536 return store_E_None;
539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */