File: vla.h

package info (click to toggle)
pymol 2.5.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 42,288 kB
  • sloc: cpp: 476,472; python: 76,538; ansic: 29,510; javascript: 6,792; sh: 47; makefile: 24
file content (260 lines) | stat: -rw-r--r-- 6,280 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
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/*
 * (c) Schrodinger, Inc.
 */

#pragma once

#include "MemoryDebug.h"
#include "pymol/memory.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <type_traits>

namespace pymol
{

/*
 * NOTE: Use this only for existing VLAs
 * otherwise, Use std::vector<T> instead!
 *
 * NOTE: safe RAII version of our PyMOL VLAs
 *
 * NOTE: allocation exceptions handled by VLA API
 */

/**
 * Variable sized array.
 *
 * Compatible with legacy VLA API (MemoryDebug.h) through implicit casts.
 *
 * Conceptually (mostly) equivalent to std::vector<T>. Differences are:
 * - no capacity(), but size() will grow in a similar fashion when calling
 *   check()
 */
template <typename T> class vla
{
#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ >= 5
  // Not available in GCC 4.8
  static_assert(std::is_trivially_copyable<T>::value, "");
#endif

  T* m_vla = nullptr;

  void swap(vla<T>& other) noexcept { std::swap(m_vla, other.m_vla); }

public:
  // implicit NULL constructor
  vla() = default;

  // NULL assignment
  vla<T>& operator=(std::nullptr_t)
  {
    freeP();
    return *this;
  }

  /**
   * Takes ownership of a legacy VLA pointer
   * @param ptr Pointer to a legacy VLA which was constructed with VLAlloc (or a related function)
   */
  template <typename U> friend vla<U> vla_take_ownership(U* ptr);

  /**
   * Construct a new zero-initialized container
   * @param size the size of the container
   */
  explicit vla(std::size_t size) { m_vla = VLACalloc(T, size); }

  // constructor with initializer list
  // Empty list constructs a NULL VLA to be consistent with default constructor
  vla(std::initializer_list<T> init)
  {
    if (init.size() == 0)
      return;
    resize(init.size());
    std::copy(init.begin(), init.end(), this->begin());
  }

  // copy constructor
  vla(const vla<T>& other) { m_vla = VLACopy2<T>(other.m_vla); }

  // copy assignment
  vla<T>& operator=(const vla<T>& other)
  {
    vla<T> tmp(other);
    swap(tmp);
    return *this;
  }

  // move constructor
  vla(vla<T>&& other) noexcept { swap(other); }

  // move assignment
  vla<T>& operator=(vla<T>&& other) noexcept
  {
    swap(other);
    return *this;
  }
  // destructor
  ~vla() { freeP(); }

  /**
   * Returns pointer to the underlying array serving as element storage.
   */
  const T* data() const { return m_vla; }
  T* data() { return m_vla; }

  /// legacy VLA cast
  operator const T*() const { return m_vla; }

  /// legacy address-of VLA cast
  T** operator&() { return &m_vla; }

  // note: VS2015 fails in various situations if this is not a template
  /// legacy pointer arithmetic
  template <typename S> const T* operator+(S i) const { return m_vla + i; }
  /// legacy pointer arithmetic
  template <typename S> T* operator+(S i) { return m_vla + i; }

  // note: VS2015 32bit fails with "overloads have similar conversions" if this is not a template
  /**
   * Returns a reference to the element at specified location @a i. No bounds
   * checking is performed.
   * @param i position of the element to return
   */
  template <typename S> T& operator[](S i) { return m_vla[i]; }
  template <typename S> const T& operator[](S i) const { return m_vla[i]; }

  /// legacy VLA member access
  T* operator->() { return m_vla; }
  /// legacy VLA member access
  const T* operator->() const { return m_vla; }

  /**
   * checks whether the owned pointer is not nullptr
   */
  explicit operator bool() const { return m_vla; }

  /**
   * Resizes the container to contain @a newSize elements.
   * If this didn't manage any data yet, a new zero-initialized buffer will be
   * allocated. Otherwise new elements will only be zero-initialized if the
   * first allocation was done with VLACalloc.
   * @param newSize new size of the container
   */
  void resize(std::size_t newSize)
  {
    if (m_vla == nullptr) {
      m_vla = VLACalloc(T, newSize);
    } else {
      VLASize(m_vla, T, newSize);
    }
  }

  /**
   * Returns the number of elements in the container
   */
  std::size_t size() const
  {
    if (m_vla == nullptr) {
      return 0;
    }
    return VLAGetSize(m_vla);
  }

  /**
   * Grow the container size if index @a i is out-of-bounds.
   * @post size() > i
   * @return pointer to element @a i
   * @pre operator bool() != false
   */
  T* check(std::size_t i)
  {
    assert(m_vla != nullptr);
    VLACheck(m_vla, T, i);
    return m_vla + i;
  }

  /**
   * Erases all elements from the container and frees the underlying buffer.
   * @post size() == 0
   * @post operator bool() == false
   */
  void freeP()
  {
    if (m_vla != nullptr) {
      VLAFreeP(m_vla);
    }
  }

  T* begin() { return m_vla; }
  T* end() { return m_vla + size(); }
  const T* begin() const { return m_vla; }
  const T* end() const { return m_vla + size(); }

  /**
   * Unlike resize(), won't shrink the size, and unlike check(), can be
   * called on empty container.
   * @post size() >= count
   * @post operator bool() != false
   */
  void reserve(std::size_t count)
  {
    if (m_vla == nullptr) {
      m_vla = VLACalloc(T, count);
    } else if (count != 0) {
      VLACheck(m_vla, T, count - 1);
    }
  }

  /**
   * Inserts 'count' number of elements to the vla at a given index
   * @param index position of the vla where elements are added
   * @param count number of elements added
   */
  void insert(int index, int count)
  {
    m_vla = static_cast<T*>(VLAInsertRaw(m_vla, index, count));
  }

  /**
   * Removes 'count' number of elements to the vla at a given index
   * @param index position of the vla where elements are removed
   * @param count number of elements removed
   */
  void erase(int index, int count)
  {
    m_vla = static_cast<T*>(VLADeleteRaw(m_vla, index, count));
  }
};

template <typename U> vla<U> vla_take_ownership(U* ptr)
{
  vla<U> instance;
  instance.m_vla = ptr;
  return instance;
}
} // namespace pymol

template <typename T> pymol::vla<T> VLACopy2(const pymol::vla<T>& v)
{
  return v; // calls copy constructor
}

template <typename T> void VLACheck2(pymol::vla<T>& v, size_t pos)
{
  v.check(pos);
}

template <typename T> void VLASize2(pymol::vla<T>& v, size_t size)
{
  v.resize(size);
}

template <typename T> void VLAFreeP(pymol::vla<T>& v)
{
  v.freeP();
}

// vi:sw=2:expandtab