File: FixedSizeSet.h

package info (click to toggle)
snap-aligner 1.0.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 4,988 kB
  • sloc: cpp: 36,500; ansic: 5,239; python: 227; makefile: 85; sh: 28
file content (131 lines) | stat: -rw-r--r-- 3,398 bytes parent folder | download | duplicates (5)
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
128
129
130
131
#pragma once

#include "Compat.h"
#include "BigAlloc.h"
#include "FixedSizeMap.h"
#include "exit.h"
#include "Error.h"


// 
// A fixed-capacity hash set that allows for efficient clearing and reuse through epochs
// and does not perform any memory allocation.
//
// This class only allows the capacity to be a power of 2.
//
template< typename K, typename Hash = NumericHash<K> >
class FixedSizeSet
{
public:
    FixedSizeSet(int capacity_ = 16): entries(NULL), size(0) {
        reserve(capacity_);
    }

    ~FixedSizeSet() {
        delete[] entries;
    }
    
    void reserve(int capacity) {
        if (!isPowerOf2(capacity)) {
            WriteErrorMessage("FixedSizeSet capacity must be a power of 2\n");
            soft_exit(1);
        }
        if (entries != NULL) {
            if (size > 0) {
                WriteErrorMessage("reserve() called on a non-empty FixedSizeSet\n");
                soft_exit(1);
            }
            delete[] entries;
        }
        this->capacity = capacity;
        this->mask = capacity - 1;
        entries = new Entry[capacity];
        for (int i = 0; i < capacity; i++) {
            entries[i].epoch = 0;
        }
        epoch = 1;
    }
    
    void clear() {
        size = 0;
        epoch++;
        if (epoch > 100000000) {
            // Reset the epoch of every bucket to 0 and the current epoch to 1
            for (int i = 0; i < capacity; i++) {
                entries[i].epoch = 0;
            }
            epoch = 1;
        }
    }
    
    inline bool contains(K key) {
        unsigned pos = hash(key) & mask;
        int i = 1;
        while (true) {
            if (entries[pos].epoch != epoch) {
                return false;
            } else if (entries[pos].key == key) {
                return true;
            } else {
                pos = (pos + i) & mask;
                i++;
            }
        }
    }

    inline void add(K key) {
        _ASSERT(size < capacity);
        unsigned pos = hash(key) & mask;
        int i = 1;
        while (true) {
            if (entries[pos].epoch != epoch) {
                entries[pos].key = key;
                entries[pos].epoch = epoch;
                size++;
                if (size >= capacity) { // Can't be exactly equal, because then contains with a non-existant element infinite loops
                    WriteErrorMessage("FixedSizeSet overflowed.  Code bug.\n");
                    soft_exit(1);
                }
                return;
            } else if (entries[pos].key == key) {
                return;
            } else {
                pos = (pos + i) & mask;
                i++;
            }
        }
    }
    
    void *operator new(size_t size) {return BigAlloc(size);}
    void operator delete(void *ptr) {BigDealloc(ptr);}

private:
    struct Entry {
        K key;
        int epoch;

        void *operator new[](size_t size) {return BigAlloc(size);}
        void operator delete[](void *ptr) {BigDealloc(ptr);}
    };
    
    Entry *entries;
    int capacity;
    int size;
    int maxSize;
    int mask;
    int epoch;
    Hash hash;
    
    bool isPowerOf2(int n) {
        while (n > 0) {
            if (n == 1) {
                return true;
            } else if (n % 2 == 1) {
                return false;
            } else {
                n /= 2;
            }
        }
        return false;
    }
};