mirror of
https://github.com/darlinghq/darling-bmalloc.git
synced 2024-11-23 04:19:41 +00:00
238 lines
5.8 KiB
C++
238 lines
5.8 KiB
C++
/*
|
|
* Copyright (C) 2014 Apple Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef Vector_h
|
|
#define Vector_h
|
|
|
|
#include "BInline.h"
|
|
#include "VMAllocate.h"
|
|
#include <cstddef>
|
|
#include <cstring>
|
|
|
|
namespace bmalloc {
|
|
|
|
// A replacement for std::vector that allocates using vmAllocate instead of
|
|
// malloc, shrinks automatically, and supports "popping" from the middle.
|
|
|
|
template<typename T>
|
|
class Vector {
|
|
static_assert(std::is_trivially_destructible<T>::value, "Vector must have a trivial destructor.");
|
|
public:
|
|
typedef T* iterator;
|
|
typedef const T* const_iterator;
|
|
|
|
Vector();
|
|
Vector(Vector&&);
|
|
~Vector();
|
|
|
|
iterator begin() { return m_buffer; }
|
|
iterator end() { return m_buffer + m_size; }
|
|
|
|
size_t size() { return m_size; }
|
|
size_t capacity() { return m_capacity; }
|
|
|
|
T& operator[](size_t);
|
|
T& last() { return m_buffer[m_size - 1]; }
|
|
|
|
void push(const T&);
|
|
|
|
T pop();
|
|
T pop(size_t);
|
|
T pop(const_iterator it) { return pop(it - begin()); }
|
|
|
|
void insert(iterator, const T&);
|
|
T remove(iterator);
|
|
|
|
void grow(size_t);
|
|
void shrink(size_t);
|
|
void resize(size_t);
|
|
|
|
void shrinkToFit();
|
|
|
|
private:
|
|
static constexpr size_t growFactor = 2;
|
|
static constexpr size_t shrinkFactor = 4;
|
|
static size_t initialCapacity() { return vmPageSize() / sizeof(T); }
|
|
|
|
void growCapacity();
|
|
void shrinkCapacity();
|
|
void reallocateBuffer(size_t);
|
|
|
|
T* m_buffer;
|
|
size_t m_size;
|
|
size_t m_capacity;
|
|
};
|
|
|
|
template<typename T>
|
|
inline Vector<T>::Vector()
|
|
: m_buffer(nullptr)
|
|
, m_size(0)
|
|
, m_capacity(0)
|
|
{
|
|
}
|
|
|
|
template<typename T>
|
|
inline Vector<T>::Vector(Vector&& other)
|
|
: m_buffer(other.m_buffer)
|
|
, m_size(other.m_size)
|
|
, m_capacity(other.m_capacity)
|
|
{
|
|
other.m_buffer = nullptr;
|
|
other.m_size = 0;
|
|
other.m_capacity = 0;
|
|
}
|
|
|
|
template<typename T>
|
|
Vector<T>::~Vector()
|
|
{
|
|
if (m_buffer)
|
|
vmDeallocate(m_buffer, vmSize(m_capacity * sizeof(T)));
|
|
}
|
|
|
|
template<typename T>
|
|
inline T& Vector<T>::operator[](size_t i)
|
|
{
|
|
BASSERT(i < m_size);
|
|
return m_buffer[i];
|
|
}
|
|
|
|
template<typename T>
|
|
BINLINE void Vector<T>::push(const T& value)
|
|
{
|
|
if (m_size == m_capacity)
|
|
growCapacity();
|
|
m_buffer[m_size++] = value;
|
|
}
|
|
|
|
template<typename T>
|
|
inline T Vector<T>::pop()
|
|
{
|
|
BASSERT(m_size);
|
|
T value = m_buffer[m_size - 1];
|
|
shrink(m_size - 1);
|
|
return value;
|
|
}
|
|
|
|
template<typename T>
|
|
inline T Vector<T>::pop(size_t i)
|
|
{
|
|
BASSERT(i < m_size);
|
|
std::swap(m_buffer[i], last());
|
|
return pop();
|
|
}
|
|
|
|
template<typename T>
|
|
void Vector<T>::insert(iterator it, const T& value)
|
|
{
|
|
size_t index = it - begin();
|
|
size_t moveCount = end() - it;
|
|
|
|
grow(m_size + 1);
|
|
std::memmove(&m_buffer[index + 1], &m_buffer[index], moveCount * sizeof(T));
|
|
|
|
m_buffer[index] = value;
|
|
}
|
|
|
|
template<typename T>
|
|
T Vector<T>::remove(iterator it)
|
|
{
|
|
size_t index = it - begin();
|
|
size_t moveCount = end() - it - 1;
|
|
|
|
T result = *it;
|
|
|
|
std::memmove(&m_buffer[index], &m_buffer[index + 1], moveCount * sizeof(T));
|
|
shrink(m_size - 1);
|
|
|
|
return result;
|
|
}
|
|
|
|
template<typename T>
|
|
inline void Vector<T>::grow(size_t size)
|
|
{
|
|
BASSERT(size >= m_size);
|
|
while (m_size < size)
|
|
push(T());
|
|
}
|
|
|
|
template<typename T>
|
|
inline void Vector<T>::shrink(size_t size)
|
|
{
|
|
BASSERT(size <= m_size);
|
|
m_size = size;
|
|
if (m_size < m_capacity / shrinkFactor && m_capacity > initialCapacity())
|
|
shrinkCapacity();
|
|
}
|
|
|
|
template<typename T>
|
|
inline void Vector<T>::resize(size_t size)
|
|
{
|
|
if (size <= m_size)
|
|
shrink(size);
|
|
else
|
|
grow(size);
|
|
}
|
|
|
|
template<typename T>
|
|
void Vector<T>::reallocateBuffer(size_t newCapacity)
|
|
{
|
|
RELEASE_BASSERT(newCapacity < std::numeric_limits<size_t>::max() / sizeof(T));
|
|
|
|
size_t vmSize = bmalloc::vmSize(newCapacity * sizeof(T));
|
|
T* newBuffer = vmSize ? static_cast<T*>(vmAllocate(vmSize)) : nullptr;
|
|
if (m_buffer) {
|
|
std::memcpy(newBuffer, m_buffer, m_size * sizeof(T));
|
|
vmDeallocate(m_buffer, bmalloc::vmSize(m_capacity * sizeof(T)));
|
|
}
|
|
|
|
m_buffer = newBuffer;
|
|
m_capacity = vmSize / sizeof(T);
|
|
}
|
|
|
|
template<typename T>
|
|
BNO_INLINE void Vector<T>::shrinkCapacity()
|
|
{
|
|
size_t newCapacity = max(initialCapacity(), m_capacity / shrinkFactor);
|
|
reallocateBuffer(newCapacity);
|
|
}
|
|
|
|
template<typename T>
|
|
BNO_INLINE void Vector<T>::growCapacity()
|
|
{
|
|
size_t newCapacity = max(initialCapacity(), m_size * growFactor);
|
|
reallocateBuffer(newCapacity);
|
|
}
|
|
|
|
template<typename T>
|
|
void Vector<T>::shrinkToFit()
|
|
{
|
|
if (m_size < m_capacity)
|
|
reallocateBuffer(m_size);
|
|
}
|
|
|
|
} // namespace bmalloc
|
|
|
|
#endif // Vector_h
|