dd6c13abb0
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
164 lines
4.6 KiB
C++
164 lines
4.6 KiB
C++
/*
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
Author: Leonardo de Moura
|
|
*/
|
|
#pragma once
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
#include "util/debug.h"
|
|
|
|
namespace lean {
|
|
/**
|
|
\brief Very similar to std::vector, but stores elements on the
|
|
system stack when collection has less than \c INITIAL_SIZE.
|
|
This collection is useful when writing functions that need
|
|
temporary storage.
|
|
*/
|
|
template<typename T, unsigned INITIAL_SIZE = 16>
|
|
class buffer {
|
|
protected:
|
|
T * m_buffer;
|
|
unsigned m_pos;
|
|
unsigned m_capacity;
|
|
char m_initial_buffer[INITIAL_SIZE * sizeof(T)];
|
|
|
|
void free_memory() {
|
|
if (m_buffer != reinterpret_cast<T*>(m_initial_buffer))
|
|
delete[] reinterpret_cast<char*>(m_buffer);
|
|
}
|
|
|
|
void expand() {
|
|
unsigned new_capacity = m_capacity << 1;
|
|
char * new_buffer = new char[sizeof(T) * new_capacity];
|
|
std::memcpy(new_buffer, static_cast<void*>(m_buffer), m_pos * sizeof(T));
|
|
free_memory();
|
|
m_buffer = reinterpret_cast<T*>(new_buffer);
|
|
m_capacity = new_capacity;
|
|
}
|
|
|
|
void destroy_elements() {
|
|
std::for_each(begin(), end(), [](T & e) { e.~T(); });
|
|
}
|
|
|
|
void destroy() {
|
|
destroy_elements();
|
|
free_memory();
|
|
}
|
|
|
|
public:
|
|
typedef T value_type;
|
|
typedef T * iterator;
|
|
typedef T const * const_iterator;
|
|
|
|
buffer():
|
|
m_buffer(reinterpret_cast<T *>(m_initial_buffer)),
|
|
m_pos(0),
|
|
m_capacity(INITIAL_SIZE) {
|
|
}
|
|
|
|
buffer(buffer const & source):
|
|
m_buffer(reinterpret_cast<T *>(m_initial_buffer)),
|
|
m_pos(0),
|
|
m_capacity(INITIAL_SIZE) {
|
|
std::for_each(source.begin(), source.end(), [=](T const & e) { push_back(e); });
|
|
}
|
|
|
|
~buffer() { destroy(); }
|
|
|
|
buffer & operator=(buffer const & source) {
|
|
clear();
|
|
std::for_each(source.begin(), source.end(), [=](T const & e) { push_back(e); });
|
|
return *this;
|
|
}
|
|
|
|
bool operator==(buffer const & other) const {
|
|
if (size() != other.size()) {
|
|
return false;
|
|
} else {
|
|
for (unsigned i = 0; i < size(); i++) {
|
|
if (operator[](i) != other[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool operator!=(buffer const & other) const {
|
|
return !operator==(other);
|
|
}
|
|
|
|
T const & back() const { lean_assert(!empty() && m_pos > 0); return m_buffer[m_pos - 1]; }
|
|
T & back() { lean_assert(!empty() && m_pos > 0); return m_buffer[m_pos - 1]; }
|
|
T & operator[](unsigned idx) { lean_assert(idx < size()); return m_buffer[idx]; }
|
|
T const & operator[](unsigned idx) const { lean_assert(idx < size()); return m_buffer[idx]; }
|
|
void clear() { destroy_elements(); m_pos = 0; }
|
|
unsigned size() const { return m_pos; }
|
|
T const * data() const { return m_buffer; }
|
|
T * data() { return m_buffer; }
|
|
bool empty() const { return m_pos == 0; }
|
|
iterator begin() { return m_buffer; }
|
|
iterator end() { return m_buffer + size(); }
|
|
const_iterator begin() const { return m_buffer; }
|
|
const_iterator end() const { return m_buffer + size(); }
|
|
|
|
void push_back(T const & elem) {
|
|
if (m_pos >= m_capacity)
|
|
expand();
|
|
new (m_buffer + m_pos) T(elem);
|
|
m_pos++;
|
|
}
|
|
|
|
template<typename... Args>
|
|
void emplace_back(Args&&... args) {
|
|
if (m_pos >= m_capacity)
|
|
expand();
|
|
new (m_buffer + m_pos) T(args...);
|
|
m_pos++;
|
|
}
|
|
|
|
void pop_back() {
|
|
back().~T();
|
|
m_pos--;
|
|
}
|
|
|
|
void append(unsigned sz, T const * elems) {
|
|
for (unsigned i = 0; i < sz; i++)
|
|
push_back(elems[i]);
|
|
}
|
|
|
|
template<typename C>
|
|
void append(C const & c) {
|
|
append(c.size(), c.data());
|
|
}
|
|
|
|
void resize(unsigned nsz, T const & elem = T()) {
|
|
unsigned sz = size();
|
|
if (nsz > sz) {
|
|
for (unsigned i = sz; i < nsz; i++)
|
|
push_back(elem);
|
|
} else if (nsz < sz) {
|
|
for (unsigned i = nsz; i < sz; i++)
|
|
pop_back();
|
|
}
|
|
lean_assert(size() == nsz);
|
|
}
|
|
|
|
void erase(unsigned idx) {
|
|
lean_assert(idx < size());
|
|
for (unsigned i = idx+1; i < size(); i++)
|
|
m_buffer[i-1] = m_buffer[i];
|
|
m_pos--;
|
|
}
|
|
|
|
void shrink(unsigned nsz) {
|
|
unsigned sz = size();
|
|
lean_assert(nsz <= sz);
|
|
for (unsigned i = nsz; i < sz; i++)
|
|
pop_back();
|
|
lean_assert(size() == nsz);
|
|
}
|
|
};
|
|
|
|
}
|