Kaydet (Commit) 8c1f2d28 authored tarafından Herbert Dürr's avatar Herbert Dürr

#i122208# replace the binaryurp cache for improved C++ compatibility

The C++ standards allows that the instantiation of incomplete types fails. The
Map::iterator in binaryurp Cache's Entry members had this problem. This rewrite
makes the code work with all compliant C++ compilers/STLs such as clang/libc++.
A Cache variant using an unordered_map is also provided and may be faster.
An interesting alternative would be to use boost's multi_index_container.
üst 624d138a
......@@ -27,7 +27,12 @@
#include "sal/config.h"
#include <cstddef>
#include <map>
#include <list>
#ifdef USE_UNORDERED_MAP
#include <unordered_map>
#else
#include <map>
#endif
#include "boost/noncopyable.hpp"
#include "osl/diagnose.h"
......@@ -41,90 +46,66 @@ enum { size = 256, ignore = 0xFFFF };
}
template< typename T > class Cache: private boost::noncopyable {
template< typename T > class Cache : private boost::noncopyable {
public:
typedef sal_uInt16 IdxType;
explicit Cache(std::size_t size):
size_(size), first_(map_.end()), last_(map_.end())
size_(size)
{
OSL_ASSERT(size < cache::ignore);
}
sal_uInt16 add(T const & content, bool * found) {
OSL_ASSERT(found != 0);
typename Map::iterator i(map_.find(content));
*found = i != map_.end();
if (i == map_.end()) {
typename Map::size_type n = map_.size();
if (n < size_) {
i =
(map_.insert(
typename Map::value_type(
content,
Entry(
static_cast< sal_uInt16 >(n), map_.end(),
first_)))).
first;
if (first_ == map_.end()) {
last_ = i;
} else {
first_->second.prev = i;
}
first_ = i;
} else if (last_ != map_.end()) {
i =
(map_.insert(
typename Map::value_type(
content,
Entry(last_->second.index, map_.end(), first_)))).
first;
first_->second.prev = i;
first_ = i;
typename Map::iterator j(last_);
last_ = last_->second.prev;
last_->second.next = map_.end();
map_.erase(j);
} else {
// Reached iff size_ == 0:
return cache::ignore;
}
} else if (i != first_) {
// Move to front (reached only if size_ > 1):
i->second.prev->second.next = i->second.next;
if (i->second.next == map_.end()) {
last_ = i->second.prev;
} else {
i->second.next->second.prev = i->second.prev;
}
i->second.prev = map_.end();
i->second.next = first_;
first_->second.prev = i;
first_ = i;
}
return i->second.index;
IdxType add( const T& rContent, bool* pbFound) {
OSL_ASSERT( pbFound != NULL);
if( !size_) {
*pbFound = false;
return cache::ignore;
}
// try to insert into the map
list_.push_front( rContent); // create a temp entry
typedef std::pair<typename LruList::iterator, IdxType> MappedType;
typedef std::pair<typename LruItMap::iterator,bool> MapPair;
MapPair aMP = map_.insert( MappedType( list_.begin(), 0));
*pbFound = !aMP.second;
if( !aMP.second) { // insertion not needed => found the entry
list_.pop_front(); // remove the temp entry
list_.splice( list_.begin(), list_, aMP.first->first); // the found entry is moved to front
return aMP.first->second;
}
private:
struct Entry;
typedef std::map< T, Entry > Map;
struct Entry {
sal_uInt16 index;
typename Map::iterator prev;
typename Map::iterator next;
// test insertion successful => it was new so we keep it
IdxType n = static_cast<IdxType>( map_.size() - 1);
if( n >= size_) { // cache full => replace the LRU entry
// find the least recently used element in the map
typename LruItMap::iterator it = map_.find( --list_.end());
n = it->second;
map_.erase( it); // remove it from the map
list_.pop_back(); // remove from the list
}
aMP.first->second = n;
return n;
}
Entry(
sal_uInt16 theIndex, typename Map::iterator thePrev,
typename Map::iterator theNext):
index(theIndex), prev(thePrev), next(theNext) {}
};
private:
typedef std::list<T> LruList; // last recently used list
typedef typename LruList::iterator LruListIt;
#ifdef URPCACHE_USES_UNORDERED_MAP
struct HashT{ size_t operator()( const LruListIt& rA) const { return hash(*rA;);};
struct EqualT{ bool operator()( const LruListIt& rA, const LruListIt& rB) const { return *rA==*rB;}};
typedef ::std::unordered_map< LruListIt, IdxType, HashT, EqualT > LruItMap; // a map into a LruList
#else
struct CmpT{ bool operator()( const LruListIt& rA, const LruListIt& rB) const { return (*rA<*rB);}};
typedef ::std::map< LruListIt, IdxType, CmpT > LruItMap; // a map into a LruList
#endif
std::size_t size_;
Map map_;
typename Map::iterator first_;
typename Map::iterator last_;
LruItMap map_;
LruList list_;
};
}
#endif
......@@ -36,14 +36,38 @@
namespace com { namespace sun { namespace star { namespace uno {
bool operator <(TypeDescription const & left, TypeDescription const & right) {
OSL_ASSERT(left.is() && right.is());
typelib_TypeClass tc1 = left.get()->eTypeClass;
typelib_TypeClass tc2 = right.get()->eTypeClass;
return tc1 < tc2 ||
(tc1 == tc2 &&
(rtl::OUString(left.get()->pTypeName) <
rtl::OUString(right.get()->pTypeName)));
bool operator<( const TypeDescription& rLeft, const TypeDescription& rRight) {
OSL_ASSERT( rLeft.is() && rRight.is());
const typelib_TypeDescription& rA = *rLeft.get();
const typelib_TypeDescription& rB = *rRight.get();
if( rA.eTypeClass != rA.eTypeClass)
return (rA.eTypeClass < rB.eTypeClass);
const sal_Int32 nCmp = rtl_ustr_compare_WithLength(
rA.pTypeName->buffer, rA.pTypeName->length,
rB.pTypeName->buffer, rB.pTypeName->length);
return (nCmp < 0);
}
bool TypeDescEqual::operator()( const TypeDescription& rLeft, const TypeDescription& rRight) const
{
OSL_ASSERT( rLeft.is() && rRight.is());
const typelib_TypeDescription& rA = *rLeft.get();
const typelib_TypeDescription& rB = *rRight.get();
if( rA.eTypeClass != rB.eTypeClass)
return false;
const sal_Int32 nCmp = rtl_ustr_compare_WithLength(
rA.pTypeName->buffer, rA.pTypeName->length,
rB.pTypeName->buffer, rB.pTypeName->length);
return (nCmp == 0);
}
sal_Int32 TypeDescHash::operator()( const TypeDescription& rTD) const
{
OSL_ASSERT( rTD.is());
const typelib_TypeDescription& rA = *rTD.get();
sal_Int32 h = rtl_ustr_hashCode_WithLength( rA.pTypeName->buffer, rA.pTypeName->length);
h ^= static_cast<sal_Int32>(rA.eTypeClass);
return h;
}
} } } }
......@@ -51,8 +75,8 @@ bool operator <(TypeDescription const & left, TypeDescription const & right) {
namespace rtl {
bool operator <(ByteSequence const & left, ByteSequence const & right) {
for (sal_Int32 i = 0; i != std::min(left.getLength(), right.getLength());
++i)
const sal_Int32 nLen = std::min( left.getLength(), right.getLength());
for( sal_Int32 i = 0; i < nLen; ++i )
{
if (left[i] < right[i]) {
return true;
......@@ -65,3 +89,4 @@ bool operator <(ByteSequence const & left, ByteSequence const & right) {
}
}
......@@ -35,6 +35,10 @@ namespace com { namespace sun { namespace star { namespace uno {
bool operator <(TypeDescription const & left, TypeDescription const & right);
struct TypeDescHash { sal_Int32 operator()( const TypeDescription&) const; };
struct TypeDescEqual { bool operator()( const TypeDescription&, const TypeDescription&) const; };
} } } }
namespace rtl {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment