File: objectcache.hh

package info (click to toggle)
zbackup 1.5-4
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 868 kB
  • sloc: cpp: 6,957; ansic: 468; python: 207; makefile: 10
file content (127 lines) | stat: -rw-r--r-- 3,206 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// 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 ) const
    { 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