Path: blob/master/thirdparty/recastnavigation/Recast/Include/RecastAlloc.h
9913 views
//1// Copyright (c) 2009-2010 Mikko Mononen [email protected]2//3// This software is provided 'as-is', without any express or implied4// warranty. In no event will the authors be held liable for any damages5// arising from the use of this software.6// Permission is granted to anyone to use this software for any purpose,7// including commercial applications, and to alter it and redistribute it8// freely, subject to the following restrictions:9// 1. The origin of this software must not be misrepresented; you must not10// claim that you wrote the original software. If you use this software11// in a product, an acknowledgment in the product documentation would be12// appreciated but is not required.13// 2. Altered source versions must be plainly marked as such, and must not be14// misrepresented as being the original software.15// 3. This notice may not be removed or altered from any source distribution.16//1718#ifndef RECASTALLOC_H19#define RECASTALLOC_H2021#include "RecastAssert.h"2223#include <stdlib.h>24#include <stdint.h>2526/// Provides hint values to the memory allocator on how long the27/// memory is expected to be used.28enum rcAllocHint29{30RC_ALLOC_PERM, ///< Memory will persist after a function call.31RC_ALLOC_TEMP ///< Memory used temporarily within a function.32};3334/// A memory allocation function.35// @param[in] size The size, in bytes of memory, to allocate.36// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.37// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.38/// @see rcAllocSetCustom39typedef void* (rcAllocFunc)(size_t size, rcAllocHint hint);4041/// A memory deallocation function.42/// @param[in] ptr A pointer to a memory block previously allocated using #rcAllocFunc.43/// @see rcAllocSetCustom44typedef void (rcFreeFunc)(void* ptr);4546/// Sets the base custom allocation functions to be used by Recast.47/// @param[in] allocFunc The memory allocation function to be used by #rcAlloc48/// @param[in] freeFunc The memory de-allocation function to be used by #rcFree49///50/// @see rcAlloc, rcFree51void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc);5253/// Allocates a memory block.54///55/// @param[in] size The size, in bytes of memory, to allocate.56/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.57/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.58///59/// @see rcFree, rcAllocSetCustom60void* rcAlloc(size_t size, rcAllocHint hint);6162/// Deallocates a memory block. If @p ptr is NULL, this does nothing.63///64/// @warning This function leaves the value of @p ptr unchanged. So it still65/// points to the same (now invalid) location, and not to null.66///67/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc.68///69/// @see rcAlloc, rcAllocSetCustom70void rcFree(void* ptr);7172/// An implementation of operator new usable for placement new. The default one is part of STL (which we don't use).73/// rcNewTag is a dummy type used to differentiate our operator from the STL one, in case users import both Recast74/// and STL.75struct rcNewTag {};76inline void* operator new(size_t, const rcNewTag&, void* p) { return p; }77inline void operator delete(void*, const rcNewTag&, void*) {}7879/// Signed to avoid warnnings when comparing to int loop indexes, and common error with comparing to zero.80/// MSVC2010 has a bug where ssize_t is unsigned (!!!).81typedef intptr_t rcSizeType;82#define RC_SIZE_MAX INTPTR_MAX8384/// Macros to hint to the compiler about the likeliest branch. Please add a benchmark that demonstrates a performance85/// improvement before introducing use cases.86#if defined(__GNUC__) || defined(__clang__)87#define rcLikely(x) __builtin_expect((x), true)88#define rcUnlikely(x) __builtin_expect((x), false)89#else90#define rcLikely(x) (x)91#define rcUnlikely(x) (x)92#endif9394/// Variable-sized storage type. Mimics the interface of std::vector<T> with some notable differences:95/// * Uses rcAlloc()/rcFree() to handle storage.96/// * No support for a custom allocator.97/// * Uses signed size instead of size_t to avoid warnings in for loops: "for (int i = 0; i < foo.size(); i++)"98/// * Omits methods of limited utility: insert/erase, (bad performance), at (we don't use exceptions), operator=.99/// * assign() and the pre-sizing constructor follow C++11 semantics -- they don't construct a temporary if no value is provided.100/// * push_back() and resize() support adding values from the current vector. Range-based constructors and assign(begin, end) do not.101/// * No specialization for bool.102template <typename T, rcAllocHint H>103class rcVectorBase {104rcSizeType m_size;105rcSizeType m_cap;106T* m_data;107// Constructs a T at the give address with either the copy constructor or the default.108static void construct(T* p, const T& v) { ::new(rcNewTag(), (void*)p) T(v); }109static void construct(T* p) { ::new(rcNewTag(), (void*)p) T; }110static void construct_range(T* begin, T* end);111static void construct_range(T* begin, T* end, const T& value);112static void copy_range(T* dst, const T* begin, const T* end);113void destroy_range(rcSizeType begin, rcSizeType end);114// Creates an array of the given size, copies all of this vector's data into it, and returns it.115T* allocate_and_copy(rcSizeType size);116void resize_impl(rcSizeType size, const T* value);117// Requires: min_capacity > m_cap.118rcSizeType get_new_capacity(rcSizeType min_capacity);119public:120typedef rcSizeType size_type;121typedef T value_type;122123rcVectorBase() : m_size(0), m_cap(0), m_data(0) {}124rcVectorBase(const rcVectorBase<T, H>& other) : m_size(0), m_cap(0), m_data(0) { assign(other.begin(), other.end()); }125explicit rcVectorBase(rcSizeType count) : m_size(0), m_cap(0), m_data(0) { resize(count); }126rcVectorBase(rcSizeType count, const T& value) : m_size(0), m_cap(0), m_data(0) { resize(count, value); }127rcVectorBase(const T* begin, const T* end) : m_size(0), m_cap(0), m_data(0) { assign(begin, end); }128~rcVectorBase() { destroy_range(0, m_size); rcFree(m_data); }129130// Unlike in std::vector, we return a bool to indicate whether the alloc was successful.131bool reserve(rcSizeType size);132133void assign(rcSizeType count, const T& value) { clear(); resize(count, value); }134void assign(const T* begin, const T* end);135136void resize(rcSizeType size) { resize_impl(size, NULL); }137void resize(rcSizeType size, const T& value) { resize_impl(size, &value); }138// Not implemented as resize(0) because resize requires T to be default-constructible.139void clear() { destroy_range(0, m_size); m_size = 0; }140141void push_back(const T& value);142void pop_back() { rcAssert(m_size > 0); back().~T(); m_size--; }143144rcSizeType size() const { return m_size; }145rcSizeType capacity() const { return m_cap; }146bool empty() const { return size() == 0; }147148const T& operator[](rcSizeType i) const { rcAssert(i >= 0 && i < m_size); return m_data[i]; }149T& operator[](rcSizeType i) { rcAssert(i >= 0 && i < m_size); return m_data[i]; }150151const T& front() const { rcAssert(m_size); return m_data[0]; }152T& front() { rcAssert(m_size); return m_data[0]; }153const T& back() const { rcAssert(m_size); return m_data[m_size - 1]; }154T& back() { rcAssert(m_size); return m_data[m_size - 1]; }155const T* data() const { return m_data; }156T* data() { return m_data; }157158T* begin() { return m_data; }159T* end() { return m_data + m_size; }160const T* begin() const { return m_data; }161const T* end() const { return m_data + m_size; }162163void swap(rcVectorBase<T, H>& other);164165// Explicitly deleted.166rcVectorBase& operator=(const rcVectorBase<T, H>& other);167};168169template<typename T, rcAllocHint H>170bool rcVectorBase<T, H>::reserve(rcSizeType count) {171if (count <= m_cap) {172return true;173}174T* new_data = allocate_and_copy(count);175if (!new_data) {176return false;177}178destroy_range(0, m_size);179rcFree(m_data);180m_data = new_data;181m_cap = count;182return true;183}184template <typename T, rcAllocHint H>185T* rcVectorBase<T, H>::allocate_and_copy(rcSizeType size) {186rcAssert(RC_SIZE_MAX / static_cast<rcSizeType>(sizeof(T)) >= size);187T* new_data = static_cast<T*>(rcAlloc(sizeof(T) * size, H));188if (new_data) {189copy_range(new_data, m_data, m_data + m_size);190}191return new_data;192}193template <typename T, rcAllocHint H>194void rcVectorBase<T, H>::assign(const T* begin, const T* end) {195clear();196reserve(end - begin);197m_size = end - begin;198copy_range(m_data, begin, end);199}200template <typename T, rcAllocHint H>201void rcVectorBase<T, H>::push_back(const T& value) {202// rcLikely increases performance by ~50% on BM_rcVector_PushPreallocated,203// and by ~2-5% on BM_rcVector_Push.204if (rcLikely(m_size < m_cap)) {205construct(m_data + m_size++, value);206return;207}208209const rcSizeType new_cap = get_new_capacity(m_cap + 1);210T* data = allocate_and_copy(new_cap);211// construct between allocate and destroy+free in case value is212// in this vector.213construct(data + m_size, value);214destroy_range(0, m_size);215m_size++;216m_cap = new_cap;217rcFree(m_data);218m_data = data;219}220221template <typename T, rcAllocHint H>222rcSizeType rcVectorBase<T, H>::get_new_capacity(rcSizeType min_capacity) {223rcAssert(min_capacity <= RC_SIZE_MAX);224if (rcUnlikely(m_cap >= RC_SIZE_MAX / 2))225return RC_SIZE_MAX;226return 2 * m_cap > min_capacity ? 2 * m_cap : min_capacity;227}228229template <typename T, rcAllocHint H>230void rcVectorBase<T, H>::resize_impl(rcSizeType size, const T* value) {231if (size < m_size) {232destroy_range(size, m_size);233m_size = size;234} else if (size > m_size) {235if (size <= m_cap) {236if (value) {237construct_range(m_data + m_size, m_data + size, *value);238} else {239construct_range(m_data + m_size, m_data + size);240}241m_size = size;242} else {243const rcSizeType new_cap = get_new_capacity(size);244T* new_data = allocate_and_copy(new_cap);245// We defer deconstructing/freeing old data until after constructing246// new elements in case "value" is there.247if (value) {248construct_range(new_data + m_size, new_data + size, *value);249} else {250construct_range(new_data + m_size, new_data + size);251}252destroy_range(0, m_size);253rcFree(m_data);254m_data = new_data;255m_cap = new_cap;256m_size = size;257}258}259}260template <typename T, rcAllocHint H>261void rcVectorBase<T, H>::swap(rcVectorBase<T, H>& other) {262// TODO: Reorganize headers so we can use rcSwap here.263rcSizeType tmp_cap = other.m_cap;264rcSizeType tmp_size = other.m_size;265T* tmp_data = other.m_data;266267other.m_cap = m_cap;268other.m_size = m_size;269other.m_data = m_data;270271m_cap = tmp_cap;272m_size = tmp_size;273m_data = tmp_data;274}275// static276template <typename T, rcAllocHint H>277void rcVectorBase<T, H>::construct_range(T* begin, T* end) {278for (T* p = begin; p < end; p++) {279construct(p);280}281}282// static283template <typename T, rcAllocHint H>284void rcVectorBase<T, H>::construct_range(T* begin, T* end, const T& value) {285for (T* p = begin; p < end; p++) {286construct(p, value);287}288}289// static290template <typename T, rcAllocHint H>291void rcVectorBase<T, H>::copy_range(T* dst, const T* begin, const T* end) {292for (rcSizeType i = 0 ; i < end - begin; i++) {293construct(dst + i, begin[i]);294}295}296template <typename T, rcAllocHint H>297void rcVectorBase<T, H>::destroy_range(rcSizeType begin, rcSizeType end) {298for (rcSizeType i = begin; i < end; i++) {299m_data[i].~T();300}301}302303template <typename T>304class rcTempVector : public rcVectorBase<T, RC_ALLOC_TEMP> {305typedef rcVectorBase<T, RC_ALLOC_TEMP> Base;306public:307rcTempVector() : Base() {}308explicit rcTempVector(rcSizeType size) : Base(size) {}309rcTempVector(rcSizeType size, const T& value) : Base(size, value) {}310rcTempVector(const rcTempVector<T>& other) : Base(other) {}311rcTempVector(const T* begin, const T* end) : Base(begin, end) {}312};313template <typename T>314class rcPermVector : public rcVectorBase<T, RC_ALLOC_PERM> {315typedef rcVectorBase<T, RC_ALLOC_PERM> Base;316public:317rcPermVector() : Base() {}318explicit rcPermVector(rcSizeType size) : Base(size) {}319rcPermVector(rcSizeType size, const T& value) : Base(size, value) {}320rcPermVector(const rcPermVector<T>& other) : Base(other) {}321rcPermVector(const T* begin, const T* end) : Base(begin, end) {}322};323324325/// Legacy class. Prefer rcVector<int>.326class rcIntArray327{328rcTempVector<int> m_impl;329public:330rcIntArray() {}331rcIntArray(int n) : m_impl(n, 0) {}332void push(int item) { m_impl.push_back(item); }333void resize(int size) { m_impl.resize(size); }334void clear() { m_impl.clear(); }335int pop()336{337int v = m_impl.back();338m_impl.pop_back();339return v;340}341int size() const { return static_cast<int>(m_impl.size()); }342int& operator[](int index) { return m_impl[index]; }343int operator[](int index) const { return m_impl[index]; }344};345346/// A simple helper class used to delete an array when it goes out of scope.347/// @note This class is rarely if ever used by the end user.348template<class T> class rcScopedDelete349{350T* ptr;351public:352353/// Constructs an instance with a null pointer.354inline rcScopedDelete() : ptr(0) {}355356/// Constructs an instance with the specified pointer.357/// @param[in] p An pointer to an allocated array.358inline rcScopedDelete(T* p) : ptr(p) {}359inline ~rcScopedDelete() { rcFree(ptr); }360361/// The root array pointer.362/// @return The root array pointer.363inline operator T*() { return ptr; }364365private:366// Explicitly disabled copy constructor and copy assignment operator.367rcScopedDelete(const rcScopedDelete&);368rcScopedDelete& operator=(const rcScopedDelete&);369};370371#endif372373374