blob: 90d8637fb3945803ef77756b55f62cecedd8f76d [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#ifndef _STORE_STORBASE_HXX_
#define _STORE_STORBASE_HXX_ "$Revision: 1.10.8.4 $"
#include "sal/types.h"
#include "rtl/alloc.h"
#include "rtl/crc.h"
#include "rtl/ref.hxx"
#include "osl/diagnose.h"
#include "osl/endian.h"
#include "store/types.h"
#ifndef INCLUDED_STDDEF_H
#include <stddef.h>
#define INCLUDED_STDDEF_H
#endif
#ifndef INCLUDED_STRING_H
#include <string.h>
#define INCLUDED_STRING_H
#endif
/*========================================================================
*
* store common internals.
*
*======================================================================*/
#ifndef STORE_IMPL_ISP2
#define STORE_IMPL_ISP2(value) (((value) & ((value) - 1)) == 0)
#endif
#ifndef STORE_IMPL_CONCAT
#define STORE_IMPL_CONCAT(x, y) STORE_IMPL_CONCAT2(x,y)
#define STORE_IMPL_CONCAT2(x, y) x##y
#endif
#ifndef STORE_STATIC_ASSERT /* Compile time assertion */
namespace store
{
template< bool x > struct STATIC_ASSERTION_FAILURE;
template<> struct STATIC_ASSERTION_FAILURE< true > { enum { value = 1 }; };
template< int x > struct static_assert_test{};
} // namespace store
#define STORE_STATIC_ASSERT(pred) \
typedef \
store::static_assert_test< sizeof( store::STATIC_ASSERTION_FAILURE< (bool)(pred) > ) > \
STORE_IMPL_CONCAT(static_assert_typedef_, __LINE__)
#endif /* !STORE_STATIC_ASSERT */
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 */
/** swap.
*/
template< typename T > void swap (T & lhs, T & rhs)
{
T tmp = lhs; lhs = rhs; rhs = tmp;
}
/*========================================================================
*
* SharedCount.
*
*======================================================================*/
class SharedCount
{
long * m_pCount;
class Allocator
{
rtl_cache_type * m_cache;
public:
static Allocator & get();
long * alloc()
{
return static_cast<long*>(rtl_cache_alloc (m_cache));
}
void free (long * pCount)
{
rtl_cache_free (m_cache, pCount);
}
protected:
Allocator();
~Allocator();
};
public:
SharedCount()
: m_pCount(Allocator::get().alloc())
{
if (m_pCount != 0) (*m_pCount) = 1;
}
~SharedCount()
{
if (m_pCount != 0)
{
long new_count = --(*m_pCount);
if (new_count == 0)
Allocator::get().free(m_pCount);
}
}
void swap (SharedCount & rhs) // nothrow
{
store::swap(m_pCount, rhs.m_pCount);
}
SharedCount (SharedCount const & rhs) // nothrow
: m_pCount (rhs.m_pCount)
{
if (m_pCount != 0) ++(*m_pCount);
}
SharedCount & operator= (SharedCount const & rhs) // nothrow
{
SharedCount tmp(rhs);
swap(tmp);
return *this;
}
bool operator== (long count) const
{
return (m_pCount != 0) ? *m_pCount == count : false;
}
};
/*========================================================================
*
* OStorePageGuard.
*
*======================================================================*/
struct OStorePageGuard
{
/** Representation.
*/
sal_uInt32 m_nMagic;
sal_uInt32 m_nCRC32;
/** Construction.
*/
explicit OStorePageGuard (sal_uInt32 nMagic = 0, sal_uInt32 nCRC32 = 0)
: m_nMagic (store::htonl(nMagic)),
m_nCRC32 (store::htonl(nCRC32))
{}
void swap (OStorePageGuard & rhs)
{
store::swap(m_nMagic, rhs.m_nMagic);
store::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) );
}
};
/*========================================================================
*
* OStorePageDescriptor.
*
*======================================================================*/
#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 = STORE_PAGE_NULL,
sal_uInt16 nSize = 0,
sal_uInt16 nUsed = 0)
: m_nAddr (store::htonl(nAddr)),
m_nSize (store::htons(nSize)),
m_nUsed (store::htons(nUsed))
{}
void swap (OStorePageDescriptor & rhs)
{
store::swap(m_nAddr, rhs.m_nAddr);
store::swap(m_nSize, rhs.m_nSize);
store::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) );
}
bool operator<= (const OStorePageDescriptor & rhs) const
{
return ((m_nAddr == rhs.m_nAddr ) &&
(store::ntohs(m_nSize) <= store::ntohs(rhs.m_nSize)) );
}
bool operator< (const OStorePageDescriptor & rhs) const
{
if (m_nAddr == rhs.m_nAddr)
return (store::ntohs(m_nSize) < store::ntohs(rhs.m_nSize));
else
return (store::ntohl(m_nAddr) < store::ntohl(rhs.m_nAddr));
}
};
/*========================================================================
*
* OStorePageKey.
*
*======================================================================*/
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))
{}
void swap (OStorePageKey & rhs)
{
store::swap(m_nLow, rhs.m_nLow);
store::swap(m_nHigh, rhs.m_nHigh);
}
OStorePageKey (const OStorePageKey & rhs)
: m_nLow (rhs.m_nLow), m_nHigh (rhs.m_nHigh)
{}
OStorePageKey & operator= (const OStorePageKey & rhs)
{
m_nLow = rhs.m_nLow;
m_nHigh = rhs.m_nHigh;
return *this;
}
/** 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));
}
};
/*========================================================================
*
* OStorePageLink.
*
*======================================================================*/
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)
{
store::swap(m_nAddr, rhs.m_nAddr);
}
OStorePageLink (const OStorePageLink & rhs)
: m_nAddr (rhs.m_nAddr)
{}
OStorePageLink & operator= (const OStorePageLink & rhs)
{
m_nAddr = rhs.m_nAddr;
return *this;
}
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);
}
bool operator< (const OStorePageLink& rhs) const
{
return (store::ntohl(m_nAddr) < store::ntohl(rhs.m_nAddr));
}
/** Operation.
*/
sal_uInt32 location() const
{
return store::ntohl(m_nAddr);
}
void link (OStorePageLink & rPred)
{
// @@@ swap (rPred); @@@
OStorePageLink tmp (rPred);
rPred = *this;
*this = tmp;
}
void unlink (OStorePageLink& rPred)
{
rPred = *this;
*this = OStorePageLink();
}
};
/*========================================================================
*
* PageData.
*
*======================================================================*/
typedef struct PageData OStorePageData; // backward compat.
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;
STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= 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 rtl::IReference
{
public:
template< class T > T * construct()
{
void * page = 0; sal_uInt16 size = 0;
if (allocate (&page, &size))
{
return new(page) T(size);
}
return 0;
}
bool allocate (void ** ppPage, sal_uInt16 * pnSize)
{
allocate_Impl (ppPage, pnSize);
return ((*ppPage != 0) && (*pnSize != 0));
}
void deallocate (void * pPage)
{
if (pPage != 0)
deallocate_Impl (pPage);
}
static storeError createInstance (
rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize);
private:
/** Implementation (abstract).
*/
virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize) = 0;
virtual void deallocate_Impl (void * pPage) = 0;
};
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 = 0;
nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
m_aDescr.m_nAddr = store::htonl(nAddr);
nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
m_aGuard.m_nCRC32 = store::htonl(nCRC32);
}
/** verify (external representation).
*/
storeError verify (sal_uInt32 nAddr) const
{
sal_uInt32 nCRC32 = 0;
nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, 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;
}
storeError verifyVersion (sal_uInt32 nMagic) const
{
if (m_aGuard.m_nMagic != store::htonl(nMagic))
return store_E_WrongVersion;
else
return store_E_None;
}
};
/*========================================================================
*
* PageHolder.
*
*======================================================================*/
class PageHolder
{
SharedCount m_refcount;
PageData * m_pagedata;
typedef rtl::Reference< PageData::Allocator > allocator_type;
allocator_type m_allocator;
public:
explicit PageHolder (PageData * pagedata = 0, allocator_type const & allocator = allocator_type())
: m_refcount (),
m_pagedata (pagedata),
m_allocator(allocator)
{
OSL_ENSURE((m_pagedata == 0) || m_allocator.is(), "store::PageHolder::ctor(): pagedata w/o allocator.");
}
~PageHolder()
{
if ((m_refcount == 1) && (m_pagedata != 0))
{
// free pagedata.
OSL_ENSURE(m_allocator.is(), "store::PageHolder::dtor(): pagedata w/o allocator.");
m_allocator->deallocate (m_pagedata);
}
}
void swap (PageHolder & rhs) // nothrow
{
m_refcount.swap(rhs.m_refcount);
store::swap(m_pagedata, rhs.m_pagedata);
store::swap(m_allocator, rhs.m_allocator);
}
PageHolder (PageHolder const & rhs) // nothrow
: m_refcount (rhs.m_refcount),
m_pagedata (rhs.m_pagedata),
m_allocator(rhs.m_allocator)
{}
PageHolder & operator= (PageHolder const & rhs) // nothrow
{
PageHolder tmp (rhs);
swap(tmp);
return *this;
}
PageData * get() { return m_pagedata; }
PageData const * get() const { return m_pagedata; }
PageData * operator->()
{
OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator->(): Null pointer");
return m_pagedata;
}
PageData const * operator->() const
{
OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator->(): Null pointer");
return m_pagedata;
}
PageData & operator*()
{
OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator*(): Null pointer");
return *m_pagedata;
}
PageData const & operator*() const
{
OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator*(): Null pointer");
return *m_pagedata;
}
};
/*========================================================================
*
* PageHolderObject.
*
*======================================================================*/
template< class T >
class PageHolderObject
{
/** Representation.
*/
PageHolder m_xPage;
/** Checked cast.
*/
template< class U >
static bool isA (PageData const * p)
{
return ((p != 0) && (p->type() == U::theTypeId));
}
template< class U >
static U * dynamic_page_cast (PageData * p)
{
return isA<U>(p) ? static_cast<U*>(p) : 0;
}
template< class U >
static U const * dynamic_page_cast (PageData const * p)
{
return isA<U>(p) ? static_cast<U const *>(p) : 0;
}
public:
bool construct (rtl::Reference< PageData::Allocator > const & rxAllocator)
{
if ((m_xPage.get() == 0) && rxAllocator.is())
{
PageHolder tmp (rxAllocator->construct<T>(), rxAllocator);
m_xPage.swap (tmp);
}
return (m_xPage.get() != 0);
}
static PageHolderObject<T> createInstance (rtl::Reference< PageData::Allocator > const & rxAllocator)
{
PageHolderObject<T> tmp;
(void) tmp.construct (rxAllocator);
return tmp;
}
explicit PageHolderObject (PageHolder const & rxPage = PageHolder())
: m_xPage (rxPage)
{}
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 (m_xPage.get() != 0);
}
#if 1 /* EXP */
PageHolder & get() { return m_xPage; }
PageHolder const & get() const { return m_xPage; }
#endif /* EXP */
T * operator->()
{
T * pImpl = dynamic_page_cast<T>(m_xPage.get());
OSL_PRECOND(pImpl != 0, "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 != 0, "store::PageHolder<T>::operator*(): Null pointer");
return pImpl;
}
T & operator*()
{
T * pImpl = dynamic_page_cast<T>(m_xPage.get());
OSL_PRECOND(pImpl != 0, "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 != 0, "store::PageHolder<T>::operator*(): Null pointer");
return (*pImpl);
}
static storeError guard (PageHolder & 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 != 0, "store::PageHolder<T>::guard(): Null pointer");
pImpl->guard();
return store_E_None;
}
static storeError verify (PageHolder 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();
}
};
/*========================================================================
*
* PageObject.
*
*======================================================================*/
#if 1 /* EXP */
class PageObject
{
public:
explicit PageObject (PageHolder const & rxPage = PageHolder())
: m_xPage (rxPage), m_bDirty (false)
{}
virtual ~PageObject()
{}
PageHolder & get() { return m_xPage; }
PageHolder const & get() const { return m_xPage; }
void clean() { m_bDirty = false; }
void touch() { m_bDirty = true; }
sal_uInt32 location() const
{
PageData const * pagedata = m_xPage.get();
return (pagedata != 0) ? pagedata->location() : STORE_PAGE_NULL;
}
void location (sal_uInt32 nAddr)
{
PageData * pagedata = m_xPage.get();
if (pagedata != 0)
pagedata->location (nAddr);
}
protected:
PageHolder m_xPage;
bool m_bDirty;
virtual storeError guard (sal_uInt32 nAddr) = 0;
virtual storeError verify (sal_uInt32 nAddr) const = 0;
};
#endif /* EXP */
class OStorePageBIOS;
class OStorePageObject
{
typedef OStorePageData page;
public:
/** Allocation.
*/
static void * operator new (size_t n) SAL_THROW(())
{
return rtl_allocateMemory (sal_uInt32(n));
}
static void operator delete (void * p, size_t) SAL_THROW(())
{
rtl_freeMemory (p);
}
/** State.
*/
inline bool dirty (void) const;
inline void clean (void);
inline void touch (void);
/** Location.
*/
inline sal_uInt32 location (void) const;
inline void location (sal_uInt32 nAddr);
protected:
/** Representation.
*/
PageHolder m_xPage;
bool m_bDirty;
/** Construction.
*/
explicit OStorePageObject (PageHolder const & rxPage = PageHolder())
: m_xPage (rxPage), m_bDirty (false)
{}
/** Destruction.
*/
virtual ~OStorePageObject (void);
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;
PageHolder tmp (rxAllocator->construct<U>(), rxAllocator);
if (!tmp.get())
return store_E_OutOfMemory;
m_xPage.swap (tmp);
return store_E_None;
}
PageHolder & get() { return m_xPage; }
PageHolder const & get() const { return m_xPage; }
virtual storeError guard (sal_uInt32 nAddr) = 0;
virtual storeError verify (sal_uInt32 nAddr) const = 0;
};
inline bool OStorePageObject::dirty (void) const
{
return m_bDirty;
}
inline void OStorePageObject::clean (void)
{
m_bDirty = false;
}
inline void OStorePageObject::touch (void)
{
m_bDirty = true;
}
inline sal_uInt32 OStorePageObject::location (void) const
{
return m_xPage->location();
}
inline void OStorePageObject::location (sal_uInt32 nAddr)
{
m_xPage->location(nAddr);
touch();
}
/*========================================================================
*
* The End.
*
*======================================================================*/
} // namespace store
#endif /* !_STORE_STORBASE_HXX_ */