2013-07-24 21:41:03 +00:00
|
|
|
/*
|
|
|
|
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>
|
2013-09-13 10:35:29 +00:00
|
|
|
#include "util/debug.h"
|
2013-07-24 21:41:03 +00:00
|
|
|
|
|
|
|
namespace lean {
|
2013-08-15 17:46:13 +00:00
|
|
|
/**
|
|
|
|
\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.
|
|
|
|
*/
|
2013-09-13 23:14:24 +00:00
|
|
|
template<typename T, unsigned INITIAL_SIZE = 16>
|
2013-07-24 21:41:03 +00:00
|
|
|
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() {
|
2015-01-06 19:14:18 +00:00
|
|
|
unsigned new_capacity = m_capacity << 1;
|
|
|
|
char * new_buffer_char = new char[sizeof(T) * new_capacity];
|
|
|
|
T * new_buffer = reinterpret_cast<T*>(new_buffer_char);
|
|
|
|
std::uninitialized_copy(m_buffer, m_buffer + m_pos, new_buffer);
|
|
|
|
destroy();
|
|
|
|
m_buffer = new_buffer;
|
2013-07-24 21:41:03 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-09-26 15:31:31 +00:00
|
|
|
bool operator==(buffer const & other) const {
|
2013-09-11 18:36:05 +00:00
|
|
|
if (size() != other.size()) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
for (unsigned i = 0; i < size(); i++) {
|
|
|
|
if (operator[](i) != other[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-26 15:31:31 +00:00
|
|
|
bool operator!=(buffer const & other) const {
|
|
|
|
return !operator==(other);
|
|
|
|
}
|
|
|
|
|
2013-07-24 21:41:03 +00:00
|
|
|
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(); }
|
2014-10-17 21:05:36 +00:00
|
|
|
unsigned capacity() const { return m_capacity; }
|
2013-07-24 21:41:03 +00:00
|
|
|
|
|
|
|
void push_back(T const & elem) {
|
|
|
|
if (m_pos >= m_capacity)
|
|
|
|
expand();
|
|
|
|
new (m_buffer + m_pos) T(elem);
|
|
|
|
m_pos++;
|
|
|
|
}
|
|
|
|
|
2013-11-10 19:09:04 +00:00
|
|
|
template<typename... Args>
|
|
|
|
void emplace_back(Args&&... args) {
|
|
|
|
if (m_pos >= m_capacity)
|
|
|
|
expand();
|
|
|
|
new (m_buffer + m_pos) T(args...);
|
|
|
|
m_pos++;
|
|
|
|
}
|
|
|
|
|
2013-07-24 21:41:03 +00:00
|
|
|
void pop_back() {
|
|
|
|
back().~T();
|
|
|
|
m_pos--;
|
|
|
|
}
|
|
|
|
|
2013-08-02 01:52:28 +00:00
|
|
|
void append(unsigned sz, T const * elems) {
|
|
|
|
for (unsigned i = 0; i < sz; i++)
|
|
|
|
push_back(elems[i]);
|
|
|
|
}
|
|
|
|
|
2013-10-29 17:05:46 +00:00
|
|
|
template<typename C>
|
|
|
|
void append(C const & c) {
|
|
|
|
append(c.size(), c.data());
|
|
|
|
}
|
|
|
|
|
2013-09-13 23:14:24 +00:00
|
|
|
void resize(unsigned nsz, T const & elem = T()) {
|
2013-07-24 21:41:03 +00:00
|
|
|
unsigned sz = size();
|
|
|
|
if (nsz > sz) {
|
|
|
|
for (unsigned i = sz; i < nsz; i++)
|
|
|
|
push_back(elem);
|
2013-09-13 23:14:24 +00:00
|
|
|
} else if (nsz < sz) {
|
2013-07-24 21:41:03 +00:00
|
|
|
for (unsigned i = nsz; i < sz; i++)
|
|
|
|
pop_back();
|
|
|
|
}
|
|
|
|
lean_assert(size() == nsz);
|
|
|
|
}
|
|
|
|
|
2013-10-29 17:05:46 +00:00
|
|
|
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--;
|
|
|
|
}
|
|
|
|
|
2015-01-01 23:12:31 +00:00
|
|
|
void erase_elem(T const & elem) {
|
|
|
|
for (unsigned i = 0; i < size(); i++) {
|
|
|
|
if (m_buffer[i] == elem) {
|
|
|
|
erase(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 03:31:54 +00:00
|
|
|
void insert(unsigned idx, T const & elem) {
|
|
|
|
using std::swap;
|
|
|
|
lean_assert(idx <= size());
|
|
|
|
push_back(elem);
|
|
|
|
unsigned i = size();
|
|
|
|
while (i > idx + 1) {
|
|
|
|
--i;
|
|
|
|
swap(m_buffer[i], m_buffer[i-1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-24 21:41:03 +00:00
|
|
|
void shrink(unsigned nsz) {
|
|
|
|
unsigned sz = size();
|
|
|
|
lean_assert(nsz <= sz);
|
|
|
|
for (unsigned i = nsz; i < sz; i++)
|
|
|
|
pop_back();
|
|
|
|
lean_assert(size() == nsz);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|