Revert "lok: sc: make hi-dpi/zoom compatible with retrieving cell cursor"
[LibreOffice.git] / store / source / stortree.cxx
blob48dfb90c840b8caef42d0d9515d3c051f40ec9c8
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 .
20 #include <sal/config.h>
22 #include <memory>
23 #include <string.h>
25 #include "stortree.hxx"
27 #include <sal/types.h>
28 #include <sal/log.hxx>
29 #include <osl/diagnose.h>
31 #include <store/types.h>
33 #include "storbase.hxx"
34 #include "storbios.hxx"
36 using namespace store;
38 /*========================================================================
40 * OStoreBTreeNodeData implementation.
42 *======================================================================*/
44 * OStoreBTreeNodeData.
46 OStoreBTreeNodeData::OStoreBTreeNodeData (sal_uInt16 nPageSize)
47 : PageData (nPageSize)
49 base::m_aGuard.m_nMagic = store::htonl(self::theTypeId);
50 base::m_aDescr.m_nUsed = store::htons(self::thePageSize); // usageCount(0)
51 self::m_aGuard.m_nMagic = store::htonl(0); // depth(0)
53 sal_uInt16 const n = capacityCount();
54 T const t;
56 for (sal_uInt16 i = 1; i < n; i++)
58 // cppcheck-suppress arrayIndexOutOfBounds
59 m_pData[i] = t;
64 * find.
66 sal_uInt16 OStoreBTreeNodeData::find (const T& t) const
68 sal_Int32 l = 0;
69 sal_Int32 r = usageCount() - 1;
71 while (l < r)
73 sal_Int32 const m = ((l + r) >> 1);
75 if (t.m_aKey == m_pData[m].m_aKey)
76 return static_cast<sal_uInt16>(m);
77 if (t.m_aKey < m_pData[m].m_aKey)
78 r = m - 1;
79 else
80 l = m + 1;
83 sal_uInt16 const k = static_cast<sal_uInt16>(r);
84 if ((k < capacityCount()) && (t.m_aKey < m_pData[k].m_aKey))
85 return k - 1;
86 else
87 return k;
91 * insert.
93 void OStoreBTreeNodeData::insert (sal_uInt16 i, const T& t)
95 sal_uInt16 const n = usageCount();
96 sal_uInt16 const m = capacityCount();
97 if ((n < m) && (i < m))
99 // shift right.
100 memmove (&(m_pData[i + 1]), &(m_pData[i]), (n - i) * sizeof(T));
102 // insert.
103 m_pData[i] = t;
104 usageCount (n + 1);
109 * remove.
111 void OStoreBTreeNodeData::remove (sal_uInt16 i)
113 sal_uInt16 const n = usageCount();
114 if (i < n)
116 // shift left.
117 memmove (&(m_pData[i]), &(m_pData[i + 1]), (n - i - 1) * sizeof(T));
119 // truncate.
120 m_pData[n - 1] = T();
121 usageCount (n - 1);
126 * split (left half copied from right half of left page).
128 void OStoreBTreeNodeData::split (const self& rPageL)
130 sal_uInt16 const h = capacityCount() / 2;
131 memcpy (&(m_pData[0]), &(rPageL.m_pData[h]), h * sizeof(T));
132 truncate (h);
136 * truncate.
138 void OStoreBTreeNodeData::truncate (sal_uInt16 n)
140 sal_uInt16 const m = capacityCount();
141 T const t;
143 for (sal_uInt16 i = n; i < m; i++)
144 m_pData[i] = t;
145 usageCount (n);
148 /*========================================================================
150 * OStoreBTreeNodeObject implementation.
152 *======================================================================*/
154 * guard.
156 storeError OStoreBTreeNodeObject::guard (sal_uInt32 nAddr)
158 return PageHolderObject< page >::guard (m_xPage, nAddr);
162 * verify.
164 storeError OStoreBTreeNodeObject::verify (sal_uInt32 nAddr) const
166 return PageHolderObject< page >::verify (m_xPage, nAddr);
170 * split.
172 storeError OStoreBTreeNodeObject::split (
173 sal_uInt16 nIndexL,
174 PageHolderObject< page > & rxPageL,
175 OStorePageBIOS & rBIOS)
177 PageHolderObject< page > xPage (m_xPage);
178 if (!xPage.is())
179 return store_E_InvalidAccess;
181 // Check left page usage.
182 if (!rxPageL.is())
183 return store_E_InvalidAccess;
184 if (!rxPageL->querySplit())
185 return store_E_None;
187 // Construct right page.
188 PageHolderObject< page > xPageR;
189 if (!xPageR.construct (rBIOS.allocator()))
190 return store_E_OutOfMemory;
192 // Split right page off left page.
193 xPageR->split (*rxPageL);
194 xPageR->depth (rxPageL->depth());
196 // Allocate right page.
197 self aNodeR (xPageR.get());
198 storeError eErrCode = rBIOS.allocate (aNodeR);
199 if (eErrCode != store_E_None)
200 return eErrCode;
202 // Truncate left page.
203 rxPageL->truncate (rxPageL->capacityCount() / 2);
205 // Save left page.
206 self aNodeL (rxPageL.get());
207 eErrCode = rBIOS.saveObjectAt (aNodeL, aNodeL.location());
208 if (eErrCode != store_E_None)
209 return eErrCode;
211 // Insert right page.
212 OStorePageLink aLink (xPageR->location());
213 xPage->insert (nIndexL + 1, T(xPageR->m_pData[0].m_aKey, aLink));
215 // Save this page and leave.
216 return rBIOS.saveObjectAt (*this, location());
220 * remove (down to leaf node, recursive).
222 storeError OStoreBTreeNodeObject::remove (
223 sal_uInt16 nIndexL,
224 OStoreBTreeEntry & rEntryL,
225 OStorePageBIOS & rBIOS)
227 PageHolderObject< page > xImpl (m_xPage);
228 page & rPage = *xImpl;
230 // Check depth.
231 storeError eErrCode = store_E_None;
232 if (rPage.depth())
234 // Check link entry.
235 T const aEntryL (rPage.m_pData[nIndexL]);
236 if (rEntryL.compare (aEntryL) != T::COMPARE_EQUAL)
237 return store_E_InvalidAccess;
239 // Load link node.
240 self aNodeL;
241 eErrCode = rBIOS.loadObjectAt (aNodeL, aEntryL.m_aLink.location());
242 if (eErrCode != store_E_None)
243 return eErrCode;
245 // Recurse: remove from link node.
246 eErrCode = aNodeL.remove (0, rEntryL, rBIOS);
247 if (eErrCode != store_E_None)
248 return eErrCode;
250 // Check resulting link node usage.
251 PageHolderObject< page > xPageL (aNodeL.get());
252 if (xPageL->usageCount() == 0)
254 // Free empty link node.
255 eErrCode = rBIOS.free (xPageL->location());
256 if (eErrCode != store_E_None)
257 return eErrCode;
259 // Remove index.
260 rPage.remove (nIndexL);
261 touch();
263 else
266 // Relink.
267 rPage.m_pData[nIndexL].m_aKey = xPageL->m_pData[0].m_aKey;
268 touch();
271 else
273 // Check leaf entry.
274 if (rEntryL.compare (rPage.m_pData[nIndexL]) != T::COMPARE_EQUAL)
275 return store_E_NotExists;
277 // Save leaf entry.
278 rEntryL = rPage.m_pData[nIndexL];
280 // Remove leaf index.
281 rPage.remove (nIndexL);
282 touch();
285 // Check for modified node.
286 if (dirty())
288 // Save this page.
289 eErrCode = rBIOS.saveObjectAt (*this, location());
292 // Done.
293 return eErrCode;
296 /*========================================================================
298 * OStoreBTreeRootObject implementation.
300 *======================================================================*/
302 * testInvariant.
303 * Precond: root node page loaded.
305 void OStoreBTreeRootObject::testInvariant (char const * message) const
307 OSL_PRECOND(m_xPage != nullptr, "OStoreBTreeRootObject::testInvariant(): Null pointer");
308 SAL_WARN_IF( (m_xPage->location() - m_xPage->size()) != 0, "store", message);
312 * loadOrCreate.
314 storeError OStoreBTreeRootObject::loadOrCreate (
315 sal_uInt32 nAddr,
316 OStorePageBIOS & rBIOS)
318 storeError eErrCode = rBIOS.loadObjectAt (*this, nAddr);
319 if (eErrCode != store_E_NotExists)
320 return eErrCode;
322 eErrCode = construct<page>(rBIOS.allocator());
323 if (eErrCode != store_E_None)
324 return eErrCode;
326 eErrCode = rBIOS.allocate (*this);
327 if (eErrCode != store_E_None)
328 return eErrCode;
330 // Notify caller of the creation.
331 testInvariant("OStoreBTreeRootObject::loadOrCreate(): leave");
332 return store_E_Pending;
336 * change.
338 storeError OStoreBTreeRootObject::change (
339 PageHolderObject< page > & rxPageL,
340 OStorePageBIOS & rBIOS)
342 PageHolderObject< page > xPage (m_xPage);
343 testInvariant("OStoreBTreeRootObject::change(): enter");
345 // Save root location.
346 sal_uInt32 const nRootAddr = xPage->location();
348 // Construct new root.
349 if (!rxPageL.construct (rBIOS.allocator()))
350 return store_E_OutOfMemory;
352 // Save this as prev root.
353 storeError eErrCode = rBIOS.allocate (*this);
354 if (eErrCode != store_E_None)
355 return store_E_OutOfMemory;
357 // Setup new root.
358 rxPageL->depth (xPage->depth() + 1);
359 rxPageL->m_pData[0] = xPage->m_pData[0];
360 rxPageL->m_pData[0].m_aLink = xPage->location();
361 rxPageL->usageCount(1);
363 // Change root.
364 rxPageL.swap (xPage);
366 std::shared_ptr<PageData> tmp (xPage.get());
367 tmp.swap (m_xPage);
370 // Save this as new root and finish.
371 eErrCode = rBIOS.saveObjectAt (*this, nRootAddr);
372 testInvariant("OStoreBTreeRootObject::change(): leave");
373 return eErrCode;
377 * find_lookup (w/o split()).
378 * Precond: root node page loaded.
380 storeError OStoreBTreeRootObject::find_lookup (
381 OStoreBTreeNodeObject & rNode, // [out]
382 sal_uInt16 & rIndex, // [out]
383 OStorePageKey const & rKey,
384 OStorePageBIOS & rBIOS) const
386 // Init node w/ root page.
387 testInvariant("OStoreBTreeRootObject::find_lookup(): enter");
389 std::shared_ptr<PageData> tmp (m_xPage);
390 tmp.swap (rNode.get());
393 // Setup BTree entry.
394 T const entry (rKey);
396 // Check current page.
397 PageHolderObject< page > xPage (rNode.get());
398 for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >())
400 // Find next page.
401 page const & rPage = *xPage;
402 sal_uInt16 const i = rPage.find(entry);
403 sal_uInt16 const n = rPage.usageCount();
404 if (i >= n)
406 // Path to entry not exists (Must not happen(?)).
407 return store_E_NotExists;
410 // Check address.
411 sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location();
412 if (nAddr == STORE_PAGE_NULL)
414 // Path to entry not exists (Must not happen(?)).
415 return store_E_NotExists;
418 // Load next page.
419 storeError eErrCode = rBIOS.loadObjectAt (rNode, nAddr);
420 if (eErrCode != store_E_None)
421 return eErrCode;
424 // Find index.
425 page const & rPage = *xPage;
426 rIndex = rPage.find(entry);
427 if (rIndex >= rPage.usageCount())
428 return store_E_NotExists;
430 // Compare entry.
431 T::CompareResult eResult = entry.compare(rPage.m_pData[rIndex]);
432 if (eResult == T::COMPARE_LESS)
434 SAL_WARN("store", "store::BTreeRoot::find_lookup(): sort error");
435 return store_E_Unknown;
438 // Greater or Equal.
439 testInvariant("OStoreBTreeRootObject::find_lookup(): leave");
440 return store_E_None;
444 * find_insert (possibly with split()).
445 * Precond: root node page loaded.
447 storeError OStoreBTreeRootObject::find_insert (
448 OStoreBTreeNodeObject & rNode, // [out]
449 sal_uInt16 & rIndex, // [out]
450 OStorePageKey const & rKey,
451 OStorePageBIOS & rBIOS)
453 testInvariant("OStoreBTreeRootObject::find_insert(): enter");
455 // Check for RootNode split.
456 PageHolderObject< page > xRoot (m_xPage);
457 if (xRoot->querySplit())
459 PageHolderObject< page > xPageL;
461 // Change root.
462 storeError eErrCode = change (xPageL, rBIOS);
463 if (eErrCode != store_E_None)
464 return eErrCode;
466 // Split left page (prev root).
467 eErrCode = split (0, xPageL, rBIOS);
468 if (eErrCode != store_E_None)
469 return eErrCode;
472 // Init node w/ root page.
474 std::shared_ptr<PageData> tmp (m_xPage);
475 tmp.swap (rNode.get());
478 // Setup BTree entry.
479 T const entry (rKey);
481 // Check current Page.
482 PageHolderObject< page > xPage (rNode.get());
483 for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >())
485 // Find next page.
486 page const & rPage = *xPage;
487 sal_uInt16 const i = rPage.find (entry);
488 sal_uInt16 const n = rPage.usageCount();
489 if (i >= n)
491 // Path to entry not exists (Must not happen(?)).
492 return store_E_NotExists;
495 // Check address.
496 sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location();
497 if (nAddr == STORE_PAGE_NULL)
499 // Path to entry not exists (Must not happen(?)).
500 return store_E_NotExists;
503 // Load next page.
504 OStoreBTreeNodeObject aNext;
505 storeError eErrCode = rBIOS.loadObjectAt (aNext, nAddr);
506 if (eErrCode != store_E_None)
507 return eErrCode;
509 // Check for next node split.
510 PageHolderObject< page > xNext (aNext.get());
511 if (xNext->querySplit())
513 // Split next node.
514 eErrCode = rNode.split (i, xNext, rBIOS);
515 if (eErrCode != store_E_None)
516 return eErrCode;
518 // Restart.
519 continue;
522 // Let next page be current.
523 std::shared_ptr<PageData> tmp (aNext.get());
524 tmp.swap (rNode.get());
527 // Find index.
528 page const & rPage = *xPage;
529 rIndex = rPage.find(entry);
530 if (rIndex < rPage.usageCount())
532 // Compare entry.
533 T::CompareResult result = entry.compare (rPage.m_pData[rIndex]);
534 if (result == T::COMPARE_LESS)
536 SAL_WARN("store", "store::BTreeRoot::find_insert(): sort error");
537 return store_E_Unknown;
540 if (result == T::COMPARE_EQUAL)
541 return store_E_AlreadyExists;
544 // Greater or not (yet) existing.
545 testInvariant("OStoreBTreeRootObject::find_insert(): leave");
546 return store_E_None;
549 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */