diff options
Diffstat (limited to 'store/source/storbase.hxx')
-rw-r--r-- | store/source/storbase.hxx | 608 |
1 files changed, 608 insertions, 0 deletions
diff --git a/store/source/storbase.hxx b/store/source/storbase.hxx new file mode 100644 index 0000000000..207cbf40a8 --- /dev/null +++ b/store/source/storbase.hxx @@ -0,0 +1,608 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> +#include <salhelper/simplereferenceobject.hxx> + +#include <sal/types.h> + +#include <rtl/crc.h> +#include <rtl/ref.hxx> + +#include <osl/diagnose.h> +#include <osl/endian.h> + +#include <store/types.h> + +#include <cstdlib> +#include <memory> +#include <utility> + +/** @file store common internals. +*/ + +namespace store +{ + +#ifdef htons +#undef htons +#endif +#ifdef ntohs +#undef ntohs +#endif + +#ifdef htonl +#undef htonl +#endif +#ifdef ntohl +#undef ntohl +#endif + +#ifdef OSL_BIGENDIAN +inline sal_uInt16 htons (sal_uInt16 h) { return OSL_SWAPWORD(h); } +inline sal_uInt16 ntohs (sal_uInt16 n) { return OSL_SWAPWORD(n); } + +inline sal_uInt32 htonl (sal_uInt32 h) { return OSL_SWAPDWORD(h); } +inline sal_uInt32 ntohl (sal_uInt32 n) { return OSL_SWAPDWORD(n); } +#else +inline sal_uInt16 htons (sal_uInt16 h) { return h; } +inline sal_uInt16 ntohs (sal_uInt16 n) { return n; } + +inline sal_uInt32 htonl (sal_uInt32 h) { return h; } +inline sal_uInt32 ntohl (sal_uInt32 n) { return n; } +#endif /* OSL_BIGENDIAN */ + +struct OStorePageGuard +{ + /** Representation. + */ + sal_uInt32 m_nMagic; + sal_uInt32 m_nCRC32; + + /** Construction. + */ + explicit OStorePageGuard (sal_uInt32 nMagic = 0) + : m_nMagic (store::htonl(nMagic)), + m_nCRC32 (store::htonl(0)) + {} + + void swap (OStorePageGuard & rhs) + { + std::swap(m_nMagic, rhs.m_nMagic); + std::swap(m_nCRC32, rhs.m_nCRC32); + } + + OStorePageGuard (OStorePageGuard const & rhs) + : m_nMagic (rhs.m_nMagic), + m_nCRC32 (rhs.m_nCRC32) + {} + + OStorePageGuard& operator= (const OStorePageGuard& rhs) + { + m_nMagic = rhs.m_nMagic; + m_nCRC32 = rhs.m_nCRC32; + return *this; + } + + /** Comparison. + */ + bool operator== (const OStorePageGuard& rhs) const + { + return ((m_nMagic == rhs.m_nMagic) && + (m_nCRC32 == rhs.m_nCRC32) ); + } +}; + +#define STORE_PAGE_NULL (sal_uInt32(~0)) + +struct OStorePageDescriptor +{ + /** Representation. + */ + sal_uInt32 m_nAddr; + sal_uInt16 m_nSize; + sal_uInt16 m_nUsed; + + /** Construction. + */ + explicit OStorePageDescriptor ( + sal_uInt32 nAddr, + sal_uInt16 nSize, + sal_uInt16 nUsed) + : m_nAddr (store::htonl(nAddr)), + m_nSize (store::htons(nSize)), + m_nUsed (store::htons(nUsed)) + {} + + void swap (OStorePageDescriptor & rhs) + { + std::swap(m_nAddr, rhs.m_nAddr); + std::swap(m_nSize, rhs.m_nSize); + std::swap(m_nUsed, rhs.m_nUsed); + } + + OStorePageDescriptor (const OStorePageDescriptor & rhs) + : m_nAddr (rhs.m_nAddr), + m_nSize (rhs.m_nSize), + m_nUsed (rhs.m_nUsed) + {} + + OStorePageDescriptor & operator= (const OStorePageDescriptor & rhs) + { + m_nAddr = rhs.m_nAddr; + m_nSize = rhs.m_nSize; + m_nUsed = rhs.m_nUsed; + return *this; + } + + /** Comparison. + */ + bool operator== (const OStorePageDescriptor & rhs) const + { + return ((m_nAddr == rhs.m_nAddr) && + (m_nSize == rhs.m_nSize) ); + } +}; + +struct OStorePageKey +{ + /** Representation. + */ + sal_uInt32 m_nLow; + sal_uInt32 m_nHigh; + + /** Construction. + */ + explicit OStorePageKey (sal_uInt32 nLow = 0, sal_uInt32 nHigh = 0) + : m_nLow (store::htonl(nLow)), + m_nHigh (store::htonl(nHigh)) + {} + + /** Comparison. + */ + bool operator== (const OStorePageKey & rhs) const + { + return ((m_nLow == rhs.m_nLow ) && + (m_nHigh == rhs.m_nHigh) ); + } + + bool operator< (const OStorePageKey & rhs) const + { + if (m_nHigh == rhs.m_nHigh) + return (store::ntohl(m_nLow) < store::ntohl(rhs.m_nLow)); + else + return (store::ntohl(m_nHigh) < store::ntohl(rhs.m_nHigh)); + } +}; + +struct OStorePageLink +{ + /** Representation. + */ + sal_uInt32 m_nAddr; + + /** Construction. + */ + explicit OStorePageLink (sal_uInt32 nAddr = STORE_PAGE_NULL) + : m_nAddr (store::htonl(nAddr)) + {} + + void swap (OStorePageLink & rhs) + { + std::swap(m_nAddr, rhs.m_nAddr); + } + + OStorePageLink & operator= (sal_uInt32 nAddr) + { + m_nAddr = store::htonl(nAddr); + return *this; + } + + /** Comparison. + */ + bool operator== (const OStorePageLink & rhs) const + { + return (m_nAddr == rhs.m_nAddr); + } + + /** Operation. + */ + sal_uInt32 location() const + { + return store::ntohl(m_nAddr); + } + +}; + +struct PageData +{ + typedef OStorePageGuard G; + typedef OStorePageDescriptor D; + typedef OStorePageLink L; + + /** Representation. + */ + G m_aGuard; + D m_aDescr; + L m_aMarked; + L m_aUnused; + + /** theSize. + */ + static const size_t theSize = sizeof(G) + sizeof(D) + 2 * sizeof(L); + static const sal_uInt16 thePageSize = theSize; + static_assert(STORE_MINIMUM_PAGESIZE >= thePageSize, "must be at least thePageSize"); + + /** location. + */ + sal_uInt32 location() const + { + return store::ntohl(m_aDescr.m_nAddr); + } + void location (sal_uInt32 nAddr) + { + m_aDescr.m_nAddr = store::htonl(nAddr); + } + + /** size. + */ + sal_uInt16 size() const + { + return store::ntohs(m_aDescr.m_nSize); + } + + /** type. + */ + sal_uInt32 type() const + { + return store::ntohl(m_aGuard.m_nMagic); + } + + /** Allocation. + */ + class Allocator_Impl; + class Allocator : public virtual salhelper::SimpleReferenceObject + { + public: + template< class T > T * construct() + { + void * page = nullptr; + sal_uInt16 nSize = 0; + if (allocate (&page, &nSize)) + { + return new(page) T(nSize); + } + return nullptr; + } + + bool allocate (void ** ppPage, sal_uInt16 * pnSize) + { + allocate_Impl (ppPage, pnSize); + return ((*ppPage != nullptr) && (*pnSize != 0)); + } + + void deallocate (void * pPage) + { + if (pPage != nullptr) + deallocate_Impl (pPage); + } + + static storeError createInstance ( + rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); + + protected: + virtual ~Allocator() override {} + + private: + /** Implementation (abstract). + */ + virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize) = 0; + virtual void deallocate_Impl (void * pPage) = 0; + }; + + class Deallocate { + public: + explicit Deallocate(rtl::Reference<Allocator> allocator): + allocator_(std::move(allocator)) {}; + + void operator ()(void * page) const { allocator_->deallocate(page); } + + private: + rtl::Reference<Allocator> allocator_; + }; + + static void* operator new (size_t, void * p) { return p; } + static void operator delete (void * , void *) {} + + /** Construction. + */ + explicit PageData (sal_uInt16 nPageSize = thePageSize) + : m_aGuard(), + m_aDescr(STORE_PAGE_NULL, nPageSize, thePageSize), + m_aMarked(), + m_aUnused() + {} + + void swap (PageData & rhs) // nothrow + { + m_aGuard.swap(rhs.m_aGuard); + m_aDescr.swap(rhs.m_aDescr); + m_aMarked.swap(rhs.m_aMarked); + m_aUnused.swap(rhs.m_aUnused); + } + + PageData (PageData const & rhs) // nothrow + : m_aGuard (rhs.m_aGuard), + m_aDescr (rhs.m_aDescr), + m_aMarked(rhs.m_aMarked), + m_aUnused(rhs.m_aUnused) + {} + + PageData & operator= (PageData const & rhs) // nothrow + { + PageData tmp (rhs); + swap (tmp); + return *this; + } + + /** guard (external representation). + */ + void guard (sal_uInt32 nAddr) + { + sal_uInt32 nCRC32 = rtl_crc32 (0, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + m_aDescr.m_nAddr = store::htonl(nAddr); + nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, static_cast<sal_uInt32>(theSize - sizeof(G))); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify (sal_uInt32 nAddr) const + { + sal_uInt32 nCRC32 = rtl_crc32 (0, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, static_cast<sal_uInt32>(theSize - sizeof(G))); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + if (m_aDescr.m_nAddr != store::htonl(nAddr)) + return store_E_InvalidAccess; + return store_E_None; + } + +}; + +template< class T > +class PageHolderObject +{ + /** Representation. + */ + std::shared_ptr<PageData> m_xPage; + + /** Checked cast. + */ + template< class U > + static bool isA (PageData const * p) + { + return ((p != nullptr) && (p->type() == U::theTypeId)); + } + + template< class U > + static U * dynamic_page_cast (PageData * p) + { + return isA<U>(p) ? static_cast<U*>(p) : nullptr; + } + + template< class U > + static U const * dynamic_page_cast (PageData const * p) + { + return isA<U>(p) ? static_cast<U const *>(p) : nullptr; + } + +public: + bool construct (rtl::Reference< PageData::Allocator > const & rxAllocator) + { + if (!m_xPage && rxAllocator.is()) + { + std::shared_ptr<PageData> tmp (rxAllocator->construct<T>(), PageData::Deallocate(rxAllocator)); + m_xPage.swap (tmp); + } + return bool(m_xPage); + } + + explicit PageHolderObject (std::shared_ptr<PageData> xPage = std::shared_ptr<PageData>()) + : m_xPage (std::move(xPage)) + {} + + void swap (PageHolderObject<T> & rhs) + { + m_xPage.swap (rhs.m_xPage); + } + + PageHolderObject (PageHolderObject<T> const & rhs) + : m_xPage (rhs.m_xPage) + {} + + PageHolderObject<T> & operator= (PageHolderObject<T> const & rhs) + { + PageHolderObject<T> tmp (rhs); + this->swap (tmp); + return *this; + } + + bool is() const + { + return bool(m_xPage); + } + + std::shared_ptr<PageData> & get() { return m_xPage; } + std::shared_ptr<PageData> const & get() const { return m_xPage; } + + T * operator->() + { + T * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != nullptr, "store::PageHolder<T>::operator*(): Null pointer"); + return pImpl; + } + + T const * operator->() const + { + T const * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != nullptr, "store::PageHolder<T>::operator*(): Null pointer"); + return pImpl; + } + + T & operator*() + { + T * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != nullptr, "store::PageHolder<T>::operator*(): Null pointer"); + return (*pImpl); + } + + T const & operator*() const + { + T const * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != nullptr, "store::PageHolder<T>::operator*(): Null pointer"); + return (*pImpl); + } + + static storeError guard (std::shared_ptr<PageData> const & rxPage, sal_uInt32 nAddr) + { + PageData * pHead = rxPage.get(); + if (!pHead) + return store_E_InvalidAccess; + pHead->guard(nAddr); + + T * pImpl = dynamic_page_cast<T>(pHead); + OSL_PRECOND(pImpl != nullptr, "store::PageHolder<T>::guard(): Null pointer"); + pImpl->guard(); + + return store_E_None; + } + + static storeError verify (std::shared_ptr<PageData> const & rxPage, sal_uInt32 nAddr) + { + PageData const * pHead = rxPage.get(); + if (!pHead) + return store_E_InvalidAccess; + + storeError eErrCode = pHead->verify(nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + T const * pImpl = dynamic_page_cast<T>(pHead); + if (!pImpl) + return store_E_WrongVersion; + + return pImpl->verify(); + } +}; + +class OStorePageObject +{ + typedef PageData page; + +public: + /** Allocation. + */ + static void * operator new (size_t n) + { + return std::malloc(sal_uInt32(n)); + } + static void operator delete (void * p) + { + std::free (p); + } + + /** State. + */ + inline bool dirty() const; + inline void clean(); + inline void touch(); + + /** Location. + */ + inline sal_uInt32 location() const; + +protected: + /** Representation. + */ + std::shared_ptr<PageData> m_xPage; + bool m_bDirty; + + /** Construction. + */ + explicit OStorePageObject (std::shared_ptr<PageData> rxPage) + : m_xPage (std::move(rxPage)), m_bDirty (false) + {} + + /** Destruction. + */ + virtual ~OStorePageObject(); + +public: + template< class U > + PageHolderObject<U> makeHolder() const + { + return PageHolderObject<U>(m_xPage); + } + + template< class U > + storeError construct (rtl::Reference< PageData::Allocator > const & rxAllocator) + { + if (!rxAllocator.is()) + return store_E_InvalidAccess; + + std::shared_ptr<PageData> tmp (rxAllocator->construct<U>(), PageData::Deallocate(rxAllocator)); + if (!tmp) + return store_E_OutOfMemory; + + m_xPage.swap (tmp); + return store_E_None; + } + + std::shared_ptr<PageData> & get() { return m_xPage; } + + virtual storeError guard (sal_uInt32 nAddr) = 0; + virtual storeError verify (sal_uInt32 nAddr) const = 0; +}; + +inline bool OStorePageObject::dirty() const +{ + return m_bDirty; +} + +inline void OStorePageObject::clean() +{ + m_bDirty = false; +} + +inline void OStorePageObject::touch() +{ + m_bDirty = true; +} + +inline sal_uInt32 OStorePageObject::location() const +{ + return m_xPage->location(); +} + +} // namespace store + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |