Fix typo
[LibreOffice.git] / store / source / storbase.hxx
blob207cbf40a8d3cb158a006e9f5820ad635c0250c6
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 #pragma once
22 #include <sal/config.h>
23 #include <salhelper/simplereferenceobject.hxx>
25 #include <sal/types.h>
27 #include <rtl/crc.h>
28 #include <rtl/ref.hxx>
30 #include <osl/diagnose.h>
31 #include <osl/endian.h>
33 #include <store/types.h>
35 #include <cstdlib>
36 #include <memory>
37 #include <utility>
39 /** @file store common internals.
42 namespace store
45 #ifdef htons
46 #undef htons
47 #endif
48 #ifdef ntohs
49 #undef ntohs
50 #endif
52 #ifdef htonl
53 #undef htonl
54 #endif
55 #ifdef ntohl
56 #undef ntohl
57 #endif
59 #ifdef OSL_BIGENDIAN
60 inline sal_uInt16 htons (sal_uInt16 h) { return OSL_SWAPWORD(h); }
61 inline sal_uInt16 ntohs (sal_uInt16 n) { return OSL_SWAPWORD(n); }
63 inline sal_uInt32 htonl (sal_uInt32 h) { return OSL_SWAPDWORD(h); }
64 inline sal_uInt32 ntohl (sal_uInt32 n) { return OSL_SWAPDWORD(n); }
65 #else
66 inline sal_uInt16 htons (sal_uInt16 h) { return h; }
67 inline sal_uInt16 ntohs (sal_uInt16 n) { return n; }
69 inline sal_uInt32 htonl (sal_uInt32 h) { return h; }
70 inline sal_uInt32 ntohl (sal_uInt32 n) { return n; }
71 #endif /* OSL_BIGENDIAN */
73 struct OStorePageGuard
75 /** Representation.
77 sal_uInt32 m_nMagic;
78 sal_uInt32 m_nCRC32;
80 /** Construction.
82 explicit OStorePageGuard (sal_uInt32 nMagic = 0)
83 : m_nMagic (store::htonl(nMagic)),
84 m_nCRC32 (store::htonl(0))
87 void swap (OStorePageGuard & rhs)
89 std::swap(m_nMagic, rhs.m_nMagic);
90 std::swap(m_nCRC32, rhs.m_nCRC32);
93 OStorePageGuard (OStorePageGuard const & rhs)
94 : m_nMagic (rhs.m_nMagic),
95 m_nCRC32 (rhs.m_nCRC32)
98 OStorePageGuard& operator= (const OStorePageGuard& rhs)
100 m_nMagic = rhs.m_nMagic;
101 m_nCRC32 = rhs.m_nCRC32;
102 return *this;
105 /** Comparison.
107 bool operator== (const OStorePageGuard& rhs) const
109 return ((m_nMagic == rhs.m_nMagic) &&
110 (m_nCRC32 == rhs.m_nCRC32) );
114 #define STORE_PAGE_NULL (sal_uInt32(~0))
116 struct OStorePageDescriptor
118 /** Representation.
120 sal_uInt32 m_nAddr;
121 sal_uInt16 m_nSize;
122 sal_uInt16 m_nUsed;
124 /** Construction.
126 explicit OStorePageDescriptor (
127 sal_uInt32 nAddr,
128 sal_uInt16 nSize,
129 sal_uInt16 nUsed)
130 : m_nAddr (store::htonl(nAddr)),
131 m_nSize (store::htons(nSize)),
132 m_nUsed (store::htons(nUsed))
135 void swap (OStorePageDescriptor & rhs)
137 std::swap(m_nAddr, rhs.m_nAddr);
138 std::swap(m_nSize, rhs.m_nSize);
139 std::swap(m_nUsed, rhs.m_nUsed);
142 OStorePageDescriptor (const OStorePageDescriptor & rhs)
143 : m_nAddr (rhs.m_nAddr),
144 m_nSize (rhs.m_nSize),
145 m_nUsed (rhs.m_nUsed)
148 OStorePageDescriptor & operator= (const OStorePageDescriptor & rhs)
150 m_nAddr = rhs.m_nAddr;
151 m_nSize = rhs.m_nSize;
152 m_nUsed = rhs.m_nUsed;
153 return *this;
156 /** Comparison.
158 bool operator== (const OStorePageDescriptor & rhs) const
160 return ((m_nAddr == rhs.m_nAddr) &&
161 (m_nSize == rhs.m_nSize) );
165 struct OStorePageKey
167 /** Representation.
169 sal_uInt32 m_nLow;
170 sal_uInt32 m_nHigh;
172 /** Construction.
174 explicit OStorePageKey (sal_uInt32 nLow = 0, sal_uInt32 nHigh = 0)
175 : m_nLow (store::htonl(nLow)),
176 m_nHigh (store::htonl(nHigh))
179 /** Comparison.
181 bool operator== (const OStorePageKey & rhs) const
183 return ((m_nLow == rhs.m_nLow ) &&
184 (m_nHigh == rhs.m_nHigh) );
187 bool operator< (const OStorePageKey & rhs) const
189 if (m_nHigh == rhs.m_nHigh)
190 return (store::ntohl(m_nLow) < store::ntohl(rhs.m_nLow));
191 else
192 return (store::ntohl(m_nHigh) < store::ntohl(rhs.m_nHigh));
196 struct OStorePageLink
198 /** Representation.
200 sal_uInt32 m_nAddr;
202 /** Construction.
204 explicit OStorePageLink (sal_uInt32 nAddr = STORE_PAGE_NULL)
205 : m_nAddr (store::htonl(nAddr))
208 void swap (OStorePageLink & rhs)
210 std::swap(m_nAddr, rhs.m_nAddr);
213 OStorePageLink & operator= (sal_uInt32 nAddr)
215 m_nAddr = store::htonl(nAddr);
216 return *this;
219 /** Comparison.
221 bool operator== (const OStorePageLink & rhs) const
223 return (m_nAddr == rhs.m_nAddr);
226 /** Operation.
228 sal_uInt32 location() const
230 return store::ntohl(m_nAddr);
235 struct PageData
237 typedef OStorePageGuard G;
238 typedef OStorePageDescriptor D;
239 typedef OStorePageLink L;
241 /** Representation.
243 G m_aGuard;
244 D m_aDescr;
245 L m_aMarked;
246 L m_aUnused;
248 /** theSize.
250 static const size_t theSize = sizeof(G) + sizeof(D) + 2 * sizeof(L);
251 static const sal_uInt16 thePageSize = theSize;
252 static_assert(STORE_MINIMUM_PAGESIZE >= thePageSize, "must be at least thePageSize");
254 /** location.
256 sal_uInt32 location() const
258 return store::ntohl(m_aDescr.m_nAddr);
260 void location (sal_uInt32 nAddr)
262 m_aDescr.m_nAddr = store::htonl(nAddr);
265 /** size.
267 sal_uInt16 size() const
269 return store::ntohs(m_aDescr.m_nSize);
272 /** type.
274 sal_uInt32 type() const
276 return store::ntohl(m_aGuard.m_nMagic);
279 /** Allocation.
281 class Allocator_Impl;
282 class Allocator : public virtual salhelper::SimpleReferenceObject
284 public:
285 template< class T > T * construct()
287 void * page = nullptr;
288 sal_uInt16 nSize = 0;
289 if (allocate (&page, &nSize))
291 return new(page) T(nSize);
293 return nullptr;
296 bool allocate (void ** ppPage, sal_uInt16 * pnSize)
298 allocate_Impl (ppPage, pnSize);
299 return ((*ppPage != nullptr) && (*pnSize != 0));
302 void deallocate (void * pPage)
304 if (pPage != nullptr)
305 deallocate_Impl (pPage);
308 static storeError createInstance (
309 rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize);
311 protected:
312 virtual ~Allocator() override {}
314 private:
315 /** Implementation (abstract).
317 virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize) = 0;
318 virtual void deallocate_Impl (void * pPage) = 0;
321 class Deallocate {
322 public:
323 explicit Deallocate(rtl::Reference<Allocator> allocator):
324 allocator_(std::move(allocator)) {};
326 void operator ()(void * page) const { allocator_->deallocate(page); }
328 private:
329 rtl::Reference<Allocator> allocator_;
332 static void* operator new (size_t, void * p) { return p; }
333 static void operator delete (void * , void *) {}
335 /** Construction.
337 explicit PageData (sal_uInt16 nPageSize = thePageSize)
338 : m_aGuard(),
339 m_aDescr(STORE_PAGE_NULL, nPageSize, thePageSize),
340 m_aMarked(),
341 m_aUnused()
344 void swap (PageData & rhs) // nothrow
346 m_aGuard.swap(rhs.m_aGuard);
347 m_aDescr.swap(rhs.m_aDescr);
348 m_aMarked.swap(rhs.m_aMarked);
349 m_aUnused.swap(rhs.m_aUnused);
352 PageData (PageData const & rhs) // nothrow
353 : m_aGuard (rhs.m_aGuard),
354 m_aDescr (rhs.m_aDescr),
355 m_aMarked(rhs.m_aMarked),
356 m_aUnused(rhs.m_aUnused)
359 PageData & operator= (PageData const & rhs) // nothrow
361 PageData tmp (rhs);
362 swap (tmp);
363 return *this;
366 /** guard (external representation).
368 void guard (sal_uInt32 nAddr)
370 sal_uInt32 nCRC32 = rtl_crc32 (0, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
371 m_aDescr.m_nAddr = store::htonl(nAddr);
372 nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, static_cast<sal_uInt32>(theSize - sizeof(G)));
373 m_aGuard.m_nCRC32 = store::htonl(nCRC32);
376 /** verify (external representation).
378 storeError verify (sal_uInt32 nAddr) const
380 sal_uInt32 nCRC32 = rtl_crc32 (0, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
381 nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, static_cast<sal_uInt32>(theSize - sizeof(G)));
382 if (m_aGuard.m_nCRC32 != store::htonl(nCRC32))
383 return store_E_InvalidChecksum;
384 if (m_aDescr.m_nAddr != store::htonl(nAddr))
385 return store_E_InvalidAccess;
386 return store_E_None;
391 template< class T >
392 class PageHolderObject
394 /** Representation.
396 std::shared_ptr<PageData> m_xPage;
398 /** Checked cast.
400 template< class U >
401 static bool isA (PageData const * p)
403 return ((p != nullptr) && (p->type() == U::theTypeId));
406 template< class U >
407 static U * dynamic_page_cast (PageData * p)
409 return isA<U>(p) ? static_cast<U*>(p) : nullptr;
412 template< class U >
413 static U const * dynamic_page_cast (PageData const * p)
415 return isA<U>(p) ? static_cast<U const *>(p) : nullptr;
418 public:
419 bool construct (rtl::Reference< PageData::Allocator > const & rxAllocator)
421 if (!m_xPage && rxAllocator.is())
423 std::shared_ptr<PageData> tmp (rxAllocator->construct<T>(), PageData::Deallocate(rxAllocator));
424 m_xPage.swap (tmp);
426 return bool(m_xPage);
429 explicit PageHolderObject (std::shared_ptr<PageData> xPage = std::shared_ptr<PageData>())
430 : m_xPage (std::move(xPage))
433 void swap (PageHolderObject<T> & rhs)
435 m_xPage.swap (rhs.m_xPage);
438 PageHolderObject (PageHolderObject<T> const & rhs)
439 : m_xPage (rhs.m_xPage)
442 PageHolderObject<T> & operator= (PageHolderObject<T> const & rhs)
444 PageHolderObject<T> tmp (rhs);
445 this->swap (tmp);
446 return *this;
449 bool is() const
451 return bool(m_xPage);
454 std::shared_ptr<PageData> & get() { return m_xPage; }
455 std::shared_ptr<PageData> const & get() const { return m_xPage; }
457 T * operator->()
459 T * pImpl = dynamic_page_cast<T>(m_xPage.get());
460 OSL_PRECOND(pImpl != nullptr, "store::PageHolder<T>::operator*(): Null pointer");
461 return pImpl;
464 T const * operator->() const
466 T const * pImpl = dynamic_page_cast<T>(m_xPage.get());
467 OSL_PRECOND(pImpl != nullptr, "store::PageHolder<T>::operator*(): Null pointer");
468 return pImpl;
471 T & operator*()
473 T * pImpl = dynamic_page_cast<T>(m_xPage.get());
474 OSL_PRECOND(pImpl != nullptr, "store::PageHolder<T>::operator*(): Null pointer");
475 return (*pImpl);
478 T const & operator*() const
480 T const * pImpl = dynamic_page_cast<T>(m_xPage.get());
481 OSL_PRECOND(pImpl != nullptr, "store::PageHolder<T>::operator*(): Null pointer");
482 return (*pImpl);
485 static storeError guard (std::shared_ptr<PageData> const & rxPage, sal_uInt32 nAddr)
487 PageData * pHead = rxPage.get();
488 if (!pHead)
489 return store_E_InvalidAccess;
490 pHead->guard(nAddr);
492 T * pImpl = dynamic_page_cast<T>(pHead);
493 OSL_PRECOND(pImpl != nullptr, "store::PageHolder<T>::guard(): Null pointer");
494 pImpl->guard();
496 return store_E_None;
499 static storeError verify (std::shared_ptr<PageData> const & rxPage, sal_uInt32 nAddr)
501 PageData const * pHead = rxPage.get();
502 if (!pHead)
503 return store_E_InvalidAccess;
505 storeError eErrCode = pHead->verify(nAddr);
506 if (eErrCode != store_E_None)
507 return eErrCode;
509 T const * pImpl = dynamic_page_cast<T>(pHead);
510 if (!pImpl)
511 return store_E_WrongVersion;
513 return pImpl->verify();
517 class OStorePageObject
519 typedef PageData page;
521 public:
522 /** Allocation.
524 static void * operator new (size_t n)
526 return std::malloc(sal_uInt32(n));
528 static void operator delete (void * p)
530 std::free (p);
533 /** State.
535 inline bool dirty() const;
536 inline void clean();
537 inline void touch();
539 /** Location.
541 inline sal_uInt32 location() const;
543 protected:
544 /** Representation.
546 std::shared_ptr<PageData> m_xPage;
547 bool m_bDirty;
549 /** Construction.
551 explicit OStorePageObject (std::shared_ptr<PageData> rxPage)
552 : m_xPage (std::move(rxPage)), m_bDirty (false)
555 /** Destruction.
557 virtual ~OStorePageObject();
559 public:
560 template< class U >
561 PageHolderObject<U> makeHolder() const
563 return PageHolderObject<U>(m_xPage);
566 template< class U >
567 storeError construct (rtl::Reference< PageData::Allocator > const & rxAllocator)
569 if (!rxAllocator.is())
570 return store_E_InvalidAccess;
572 std::shared_ptr<PageData> tmp (rxAllocator->construct<U>(), PageData::Deallocate(rxAllocator));
573 if (!tmp)
574 return store_E_OutOfMemory;
576 m_xPage.swap (tmp);
577 return store_E_None;
580 std::shared_ptr<PageData> & get() { return m_xPage; }
582 virtual storeError guard (sal_uInt32 nAddr) = 0;
583 virtual storeError verify (sal_uInt32 nAddr) const = 0;
586 inline bool OStorePageObject::dirty() const
588 return m_bDirty;
591 inline void OStorePageObject::clean()
593 m_bDirty = false;
596 inline void OStorePageObject::touch()
598 m_bDirty = true;
601 inline sal_uInt32 OStorePageObject::location() const
603 return m_xPage->location();
606 } // namespace store
608 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */