mirror of https://github.com/vitalif/zbackup
128 lines
3.1 KiB
C++
128 lines
3.1 KiB
C++
// Copyright (c) 2012-2014 Konstantin Isakov <ikm@zbackup.org> and ZBackup contributors, see CONTRIBUTORS
|
|
// Part of ZBackup. Licensed under GNU GPLv2 or later + OpenSSL, see LICENSE
|
|
|
|
#ifndef OBJECTCACHE_HH_INCLUDED
|
|
#define OBJECTCACHE_HH_INCLUDED
|
|
|
|
#include <string>
|
|
#include <list>
|
|
#include <set>
|
|
#include <utility>
|
|
#include "sptr.hh"
|
|
#include "nocopy.hh"
|
|
|
|
/// ObjectCache allows caching dynamically-allocated objects of any type. The
|
|
/// size of the cache is upper-bound and is specified at construction-time.
|
|
/// Newly added or recently found objects are placed to the top of the internal
|
|
/// stack. When there's no space in the cache, object become removed from the
|
|
/// bottom of it
|
|
class ObjectCache: NoCopy
|
|
{
|
|
public:
|
|
ObjectCache( unsigned maxObjects );
|
|
|
|
/// Id of the object being stored in the cache
|
|
typedef std::string ObjectId;
|
|
|
|
/// Returns a reference to the stored object with the given id, or creates
|
|
/// one if none existed. The caller must know the expected type of the object
|
|
/// and specify it explicitly
|
|
template< class T >
|
|
sptr< T > & entry( ObjectId const & );
|
|
|
|
/// Removes a stored object with the given id. Returns true if the object
|
|
/// was removed, false if it didn't exist in the cache
|
|
bool remove( ObjectId const & );
|
|
|
|
/// Deletes all the objects from cache
|
|
void clear();
|
|
|
|
~ObjectCache()
|
|
{ clear(); }
|
|
|
|
private:
|
|
|
|
/// Base class for a reference to an object being stored
|
|
struct Reference: NoCopy
|
|
{
|
|
virtual ~Reference()
|
|
{}
|
|
};
|
|
|
|
/// Having this class allows to delete T via virtual destructor accessible
|
|
/// from the base Reference class
|
|
template< class T >
|
|
struct ReferenceTo: public Reference
|
|
{
|
|
sptr< T > ref;
|
|
};
|
|
|
|
struct Object
|
|
{
|
|
ObjectId id;
|
|
Reference * reference;
|
|
};
|
|
typedef std::list< Object > Objects;
|
|
|
|
struct ObjectsIteratorComp
|
|
{
|
|
bool operator () ( Objects::iterator const & x, Objects::iterator const & y )
|
|
{ return x->id < y->id; }
|
|
};
|
|
|
|
typedef std::set< Objects::iterator, ObjectsIteratorComp > ObjectMap;
|
|
|
|
unsigned maxObjects;
|
|
Objects objects;
|
|
unsigned totalObjects;
|
|
ObjectMap objectMap;
|
|
|
|
};
|
|
|
|
template< class T >
|
|
sptr< T > & ObjectCache::entry( ObjectId const & id )
|
|
{
|
|
Objects tmp;
|
|
tmp.push_back( Object() );
|
|
tmp.back().id = id;
|
|
|
|
std::pair< ObjectMap::iterator, bool > r = objectMap.insert( tmp.begin() );
|
|
|
|
if ( r.second )
|
|
{
|
|
// The object was created
|
|
|
|
// Init the reference
|
|
ReferenceTo< T > * refTo = new ReferenceTo< T >();
|
|
tmp.back().reference = refTo;
|
|
|
|
// Add the object to top of our objects
|
|
objects.splice( objects.begin(), tmp );
|
|
++totalObjects;
|
|
|
|
// evict an entry at the bottom, if needed
|
|
if ( totalObjects > maxObjects )
|
|
{
|
|
Objects::iterator i = --objects.end();
|
|
objectMap.erase( i );
|
|
Reference * ref = i->reference;
|
|
objects.pop_back();
|
|
--totalObjects;
|
|
|
|
delete ref; // We expect that it may throw
|
|
}
|
|
|
|
return refTo->ref;
|
|
}
|
|
else
|
|
{
|
|
// The object was existent
|
|
// Move it to the top
|
|
objects.splice( objects.begin(), objects, *r.first );
|
|
|
|
return dynamic_cast< ReferenceTo< T > & >( *objects.front().reference ).ref;
|
|
}
|
|
}
|
|
|
|
#endif // OBJECTCACHE_HH
|