layer0/vla.h (111 lines of code) (raw):
/*
* (c) Schrodinger, Inc.
*/
#pragma once
#include "MemoryDebug.h"
#include "LangUtil.h"
#include <algorithm>
#include <iostream>
#include <stdexcept>
#include <vector>
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
*
* Conceptually equivalent to std::vector<T>
*/
template <typename T> class vla
{
T* m_vla = nullptr;
void swap(vla<T>& other) noexcept { std::swap(m_vla, other.m_vla); }
public:
// implicit NULL constructor
vla(std::nullptr_t) {}
// constructor -- takes ownership of pointer
explicit vla(T* vla = nullptr) : m_vla(vla) {}
// constructor with size
explicit vla(std::size_t size) { m_vla = VLACalloc(T, size); }
// constructor with size and default value
vla(std::size_t size, T value)
{
m_vla = VLAlloc(T, size);
for (size_t i = 0; i < size; ++i) {
new (m_vla + i) T(value);
}
}
// constructor with initializer list
vla(std::initializer_list<T> init) : vla(init.size())
{
std::copy(init.begin(), init.end(), this->begin());
}
// constructor from std::vector
explicit vla(std::vector<T>& vec) : vla(vec.size())
{
std::copy(vec.begin(), vec.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(); }
// data access - Allows for some usability with VLA APIs
const T* data() const { return m_vla; }
T*& data() { return m_vla; }
operator const T*() const { return m_vla; }
operator T*&() { return m_vla; }
T** operator&() { return &m_vla; }
// note: VS2015 fails with operator+(size_t)
const T* operator+(int i) const { return m_vla + i; }
T* operator+(int i) { return m_vla + i; }
T& operator[](std::size_t i) { return m_vla[i]; }
const T& operator[](std::size_t i) const { return m_vla[i]; }
T* operator->() { return m_vla; }
const T* operator->() const { return m_vla; }
// checks whether the owned pointer is not nullptr
explicit operator bool() const { return m_vla; }
// Memory Management
void resize(std::size_t newSize)
{
if (m_vla == nullptr) {
m_vla = VLACalloc(T, newSize);
} else {
VLASize(m_vla, T, newSize);
}
}
std::size_t size() const
{
if (m_vla == nullptr) {
return 0;
}
return VLAGetSize(m_vla);
}
T* check(std::size_t i)
{
VLACheck(m_vla, T, i);
return m_vla + i;
}
void freeP()
{
if (m_vla != nullptr) {
pymol::destroy(begin(), end());
VLAFreeP(m_vla);
}
}
// Util functions
std::vector<T> toStdVector() const
{
return std::vector<T>(m_vla, m_vla + size());
}
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(); }
};
} // 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)
{
VLAFreeP(v.data());
}
// vi:sw=2:expandtab