aboutsummaryrefslogtreecommitdiff
path: root/src/mruset.h
blob: 9dff5694ba818e571003a9dfff885d901cf9a0c6 (plain)
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
// Copyright (c) 2012-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_MRUSET_H
#define BITCOIN_MRUSET_H

#include <set>
#include <vector>
#include <utility>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>

/** STL-like set container that only keeps the most recent N elements. */
template <typename T>
class mruset
{
public:
    typedef T key_type;
    typedef T value_type;
    typedef typename std::set<T>::iterator iterator;
    typedef typename std::set<T>::const_iterator const_iterator;
    typedef typename std::set<T>::size_type size_type;

protected:
    std::set<T> set;
    std::vector<iterator> order;
    size_type first_used;
    size_type first_unused;
    const size_type nMaxSize;

public:
    mruset(size_type nMaxSizeIn = 1) : nMaxSize(nMaxSizeIn) { clear(); }
    iterator begin() const { return set.begin(); }
    iterator end() const { return set.end(); }
    size_type size() const { return set.size(); }
    bool empty() const { return set.empty(); }
    iterator find(const key_type& k) const { return set.find(k); }
    size_type count(const key_type& k) const { return set.count(k); }
    void clear()
    {
        set.clear();
        order.assign(nMaxSize, set.end());
        first_used = 0;
        first_unused = 0;
    }
    bool inline friend operator==(const mruset<T>& a, const mruset<T>& b) { return a.set == b.set; }
    bool inline friend operator==(const mruset<T>& a, const std::set<T>& b) { return a.set == b; }
    bool inline friend operator<(const mruset<T>& a, const mruset<T>& b) { return a.set < b.set; }
    std::pair<iterator, bool> insert(const key_type& x)
    {
        std::pair<iterator, bool> ret = set.insert(x);
        if (ret.second) {
            if (set.size() == nMaxSize + 1) {
                set.erase(order[first_used]);
                order[first_used] = set.end();
                if (++first_used == nMaxSize) first_used = 0;
            }
            order[first_unused] = ret.first;
            if (++first_unused == nMaxSize) first_unused = 0;
        }
        return ret;
    }
    size_type max_size() const { return nMaxSize; }
};

/** STL-like map container that only keeps the most recent N elements. */
template <typename K, typename V>
class mrumap
{
private:
    struct key_extractor {
        typedef K result_type;
        const result_type& operator()(const std::pair<K, V>& e) const { return e.first; }
        result_type& operator()(std::pair<K, V>* e) const { return e->first; }
    };

    typedef boost::multi_index_container<
        std::pair<K, V>,
        boost::multi_index::indexed_by<
            boost::multi_index::sequenced<>,
            boost::multi_index::ordered_unique<key_extractor>
        >
    > map_type;

public:
    typedef K key_type;
    typedef std::pair<K, V> value_type;
    typedef typename map_type::iterator iterator;
    typedef typename map_type::const_iterator const_iterator;
    typedef typename map_type::size_type size_type;

protected:
    map_type m_;
    size_type max_size_;

public:
    mrumap(size_type max_size_in = 1) { clear(max_size_in); }
    iterator begin() { return m_.begin(); }
    iterator end() { return m_.end(); }
    const_iterator begin() const { return m_.begin(); }
    const_iterator end() const { return m_.end(); }
    size_type size() const { return m_.size(); }
    bool empty() const { return m_.empty(); }
    iterator find(const key_type& key) { return m_.template project<0>(boost::get<1>(m_).find(key)); }
    const_iterator find(const key_type& key) const { return m_.template project<0>(boost::get<1>(m_).find(key)); }
    size_type count(const key_type& key) const { return boost::get<1>(m_).count(key); }
    void clear(size_type max_size_in) { m_.clear(); max_size_ = max_size_in; }
    std::pair<iterator, bool> insert(const K& key, const V& value) 
    {
        std::pair<K, V> elem(key, value);
        std::pair<iterator, bool> p = m_.push_front(elem);
        if (p.second && m_.size() > max_size_) {
            m_.pop_back();
        }
        return p;
    }
    void erase(iterator it) { m_.erase(it); }
    void erase(const key_type& k) { boost::get<1>(m_).erase(k); }
    size_type max_size() const { return max_size_; }
};

#endif // BITCOIN_MRUSET_H