File: lazy_array.hh

package info (click to toggle)
salmon 0.7.2%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 4,352 kB
  • ctags: 5,243
  • sloc: cpp: 42,341; ansic: 6,252; python: 228; makefile: 207; sh: 190
file content (119 lines) | stat: -rw-r--r-- 3,781 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
/** \file */

#ifndef _LAZY_ARRAY_HH
#define _LAZY_ARRAY_HH

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <memory>

#include "cuckoohash_util.hh"

// lazy array. A fixed-size array, broken up into segments that are dynamically
// allocated, only when requested. The array size and segment size are
// pre-defined, and are powers of two. The user must make sure the necessary
// segments are allocated before accessing the array.
template <uint8_t OFFSET_BITS, uint8_t SEGMENT_BITS,
          class T, class Alloc = std::allocator<T>
          >
class lazy_array {
    static_assert(SEGMENT_BITS + OFFSET_BITS <= sizeof(size_t)*8,
                  "The number of segment and offset bits cannot exceed "
                  " the number of bits in a size_t");
private:
    static const size_t SEGMENT_SIZE = 1UL << OFFSET_BITS;
    static const size_t NUM_SEGMENTS = 1UL << SEGMENT_BITS;
    // The segments array itself is mutable, so that the const subscript
    // operator can still add segments
    mutable std::array<T*, NUM_SEGMENTS> segments_;

    void move_other_array(lazy_array&& arr) {
        clear();
        std::copy(arr.segments_.begin(), arr.segments_.end(),
                  segments_.begin());
        std::fill(arr.segments_.begin(), arr.segments_.end(), nullptr);
    }

    inline size_t get_segment(size_t i) {
        return i >> OFFSET_BITS;
    }

    static const size_t OFFSET_MASK = ((1UL << OFFSET_BITS) - 1);
    inline size_t get_offset(size_t i) {
        return i & OFFSET_MASK;
    }

public:
    lazy_array(): segments_{{nullptr}} {}

    // No copying
    lazy_array(const lazy_array&) = delete;
    lazy_array& operator=(const lazy_array&) = delete;

    // Moving is allowed
    lazy_array(lazy_array&& arr) : segments_{{nullptr}} {
        move_other_array(std::move(arr));
    }
    lazy_array& operator=(lazy_array&& arr) {
        move_other_vector(std::move(arr));
        return *this;
    }

    ~lazy_array() {
        clear();
    }

    void clear() {
        for (size_t i = 0; i < segments_.size(); ++i) {
            if (segments_[i] != nullptr) {
                destroy_array<T, Alloc>(segments_[i], SEGMENT_SIZE);
                segments_[i] = nullptr;
            }
        }
    }

    T& operator[](size_t i) {
        assert(segments_[get_segment(i)] != nullptr);
        return segments_[get_segment(i)][get_offset(i)];
    }

    const T& operator[](size_t i) const {
        assert(segments_[get_segment(i)] != nullptr);
        return segments_[get_segment(i)][get_offset(i)];
    }

    // Ensures that the array has enough segments to index target elements, not
    // exceeding the total size. The user must ensure that the array is properly
    // allocated before accessing a certain index. This saves having to check
    // every index operation.
    void allocate(size_t target) {
        assert(target <= size());
        if (target == 0) {
            return;
        }
        const size_t last_segment = get_segment(target - 1);
        for (size_t i = 0; i <= last_segment; ++i) {
            if (segments_[i] == nullptr) {
                segments_[i] = create_array<T, Alloc>(SEGMENT_SIZE);
            }
        }
    }

    // Returns the number of elements in the array that can be indexed, starting
    // contiguously from the beginning.
    size_t allocated_size() const {
        size_t num_allocated_segments = 0;
        for (;
             (num_allocated_segments < NUM_SEGMENTS &&
              segments_[num_allocated_segments] != nullptr);
             ++num_allocated_segments) {}
        return num_allocated_segments * SEGMENT_SIZE;
    }

    static constexpr size_t size() {
        return 1UL << (OFFSET_BITS + SEGMENT_BITS);
    }
};

#endif // _LAZY_ARRAY_HH