File size: 5,545 Bytes
1ce325b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#ifndef UTIL_FIXED_ARRAY_H
#define UTIL_FIXED_ARRAY_H

#include "scoped.hh"

#include <cstddef>

#include <cassert>
#include <cstdlib>

namespace util {

/**
 * Defines an array with fixed maximum size.
 *
 * Ever want an array of things but they don't have a default constructor or
 * are non-copyable?  FixedArray allows constructing one at a time.
 */
template <class T> class FixedArray {
  public:
    /** Initialize with a given size bound but do not construct the objects. */
    explicit FixedArray(std::size_t limit) {
      Init(limit);
    }

    /**
     * Constructs an instance, but does not initialize it.
     *
     * Any objects constructed in this manner must be subsequently @ref FixedArray::Init() "initialized" prior to use.
     *
     * @see FixedArray::Init()
     */
    FixedArray()
      : newed_end_(NULL)
#ifndef NDEBUG
      , allocated_end_(NULL)
#endif
    {}

    /**
     * Initialize with a given size bound but do not construct the objects.
     *
     * This method is responsible for allocating memory.
     * Objects stored in this array will be constructed in a location within this allocated memory.
     */
    void Init(std::size_t count) {
      assert(!block_.get());
      block_.reset(malloc(sizeof(T) * count));
      if (!block_.get()) throw std::bad_alloc();
      newed_end_ = begin();
#ifndef NDEBUG
      allocated_end_ = begin() + count;
#endif
    }

    /**
     * Constructs a copy of the provided array.
     *
     * @param from Array whose elements should be copied into this newly-constructed data structure.
     */
    FixedArray(const FixedArray &from) {
      std::size_t size = from.newed_end_ - static_cast<const T*>(from.block_.get());
      Init(size);
      for (std::size_t i = 0; i < size; ++i) {
        push_back(from[i]);
      }
    }

    /**
     * Frees the memory held by this object.
     */
    ~FixedArray() { clear(); }

#if __cplusplus >= 201103L
    FixedArray(FixedArray &&from)
      : block_(std::move(from.block_)),
        newed_end_(from.newed_end_)
#  ifndef NDEBUG
        , allocated_end_(from.allocated_end_)
#  endif // NDEBUG
    {
      from.newed_end_ = NULL;
#  ifndef NDEBUG
      from.allocated_end_ = NULL;
#  endif // NDEBUG
    }
#endif // C++11

    /** Gets a pointer to the first object currently stored in this data structure. */
    T *begin() { return static_cast<T*>(block_.get()); }

    /** Gets a const pointer to the last object currently stored in this data structure. */
    const T *begin() const { return static_cast<const T*>(block_.get()); }

    /** Gets a pointer to the last object currently stored in this data structure. */
    T *end() { return newed_end_; }

    /** Gets a const pointer to the last object currently stored in this data structure. */
    const T *end() const { return newed_end_; }

    /** Gets a reference to the last object currently stored in this data structure. */
    T &back() { return *(end() - 1); }

    /** Gets a const reference to the last object currently stored in this data structure. */
    const T &back() const { return *(end() - 1); }

    /** Gets the number of objects currently stored in this data structure. */
    std::size_t size() const { return end() - begin(); }

    /** Returns true if there are no objects currently stored in this data structure. */
    bool empty() const { return begin() == end(); }

    /**
     * Gets a reference to the object with index i currently stored in this data structure.
     *
     * @param i Index of the object to reference
     */
    T &operator[](std::size_t i) {
      assert(i < size());
      return begin()[i];
    }

    /**
     * Gets a const reference to the object with index i currently stored in this data structure.
     *
     * @param i Index of the object to reference
     */
    const T &operator[](std::size_t i) const {
      assert(i < size());
      return begin()[i];
    }

    /**
     * Constructs a new object using the provided parameter,
     * and stores it in this data structure.
     *
     * The memory backing the constructed object is managed by this data structure.
     * I miss C++11 variadic templates.
     */
#if __cplusplus >= 201103L
    template <typename... Construct> T *emplace_back(Construct&&... construct) {
      T *ret = end();
      new (end()) T(construct...);
      Constructed();
      return ret;
    }
    template <typename... Construct> T *push_back(Construct&&... construct) {
      T *ret = end();
      new (end()) T(construct...);
      Constructed();
      return ret;
    }
#else
    void push_back() {
      new (end()) T();
      Constructed();
    }
    template <class C> void push_back(const C &c) {
      new (end()) T(c);
      Constructed();
    }
    template <class C> void push_back(C &c) {
      new (end()) T(c);
      Constructed();
    }
    template <class C, class D> void push_back(const C &c, const D &d) {
      new (end()) T(c, d);
      Constructed();
    }
#endif

    void pop_back() {
      back().~T();
      --newed_end_;
    }

    /**
     * Removes all elements from this array.
     */
    void clear() {
      while (newed_end_ != begin())
        pop_back();
    }

  protected:
    // Always call Constructed after successful completion of new.
    void Constructed() {
      ++newed_end_;
#ifndef NDEBUG
      assert(newed_end_ <= allocated_end_);
#endif
    }

  private:
    util::scoped_malloc block_;

    T *newed_end_;

#ifndef NDEBUG
    T *allocated_end_;
#endif
};

} // namespace util

#endif // UTIL_FIXED_ARRAY_H