Revision control

++ // Copyright 2009-2021 Intel Corporation
++ // SPDX-License-Identifier: Apache-2.0
++
++ #pragma once
++
++ #include "alloc.h"
++ #include <algorithm>
++ #include <type_traits>
++
++ namespace embree
++ {
++ template<typename T, typename allocator>
++ class vector_t
++ {
++ public:
++ typedef T value_type;
++ typedef T* iterator;
++ typedef const T* const_iterator;
++
++ __forceinline vector_t ()
++ : size_active(0), size_alloced(0), items(nullptr) {}
++
++ __forceinline explicit vector_t (size_t sz)
++ : size_active(0), size_alloced(0), items(nullptr) { internal_resize_init(sz); }
++
++ template<typename M>
++ __forceinline explicit vector_t (M alloc, size_t sz)
++ : alloc(alloc), size_active(0), size_alloced(0), items(nullptr) { internal_resize_init(sz); }
++
++ __forceinline ~vector_t() {
++ clear();
++ }
++
++ __forceinline vector_t (const vector_t& other)
++ {
++ size_active = other.size_active;
++ size_alloced = other.size_alloced;
++ items = alloc.allocate(size_alloced);
++ for (size_t i=0; i<size_active; i++)
++ ::new (&items[i]) value_type(other.items[i]);
++ }
++
++ __forceinline vector_t (vector_t&& other)
++ : alloc(std::move(other.alloc))
++ {
++ size_active = other.size_active; other.size_active = 0;
++ size_alloced = other.size_alloced; other.size_alloced = 0;
++ items = other.items; other.items = nullptr;
++ }
++
++ __forceinline vector_t& operator=(const vector_t& other)
++ {
++ resize(other.size_active);
++ for (size_t i=0; i<size_active; i++)
++ items[i] = value_type(other.items[i]);
++ return *this;
++ }
++
++ __forceinline vector_t& operator=(vector_t&& other)
++ {
++ clear();
++ alloc = std::move(other.alloc);
++ size_active = other.size_active; other.size_active = 0;
++ size_alloced = other.size_alloced; other.size_alloced = 0;
++ items = other.items; other.items = nullptr;
++ return *this;
++ }
++
++ /********************** Iterators ****************************/
++
++ __forceinline iterator begin() { return items; };
++ __forceinline const_iterator begin() const { return items; };
++
++ __forceinline iterator end () { return items+size_active; };
++ __forceinline const_iterator end () const { return items+size_active; };
++
++
++ /********************** Capacity ****************************/
++
++ __forceinline bool empty () const { return size_active == 0; }
++ __forceinline size_t size () const { return size_active; }
++ __forceinline size_t capacity () const { return size_alloced; }
++
++
++ __forceinline void resize(size_t new_size) {
++ internal_resize(new_size,internal_grow_size(new_size));
++ }
++
++ __forceinline void reserve(size_t new_alloced)
++ {
++ /* do nothing if container already large enough */
++ if (new_alloced <= size_alloced)
++ return;
++
++ /* resize exact otherwise */
++ internal_resize(size_active,new_alloced);
++ }
++
++ __forceinline void shrink_to_fit() {
++ internal_resize(size_active,size_active);
++ }
++
++ /******************** Element access **************************/
++
++ __forceinline T& operator[](size_t i) { assert(i < size_active); return items[i]; }
++ __forceinline const T& operator[](size_t i) const { assert(i < size_active); return items[i]; }
++
++ __forceinline T& at(size_t i) { assert(i < size_active); return items[i]; }
++ __forceinline const T& at(size_t i) const { assert(i < size_active); return items[i]; }
++
++ __forceinline T& front() const { assert(size_active > 0); return items[0]; };
++ __forceinline T& back () const { assert(size_active > 0); return items[size_active-1]; };
++
++ __forceinline T* data() { return items; };
++ __forceinline const T* data() const { return items; };
++
++
++ /******************** Modifiers **************************/
++
++ __forceinline void push_back(const T& nt)
++ {
++ const T v = nt; // need local copy as input reference could point to this vector
++ internal_resize(size_active,internal_grow_size(size_active+1));
++ ::new (&items[size_active++]) T(v);
++ }
++
++ __forceinline void pop_back()
++ {
++ assert(!empty());
++ size_active--;
++ std::allocator_traits<decltype(alloc)>::destroy(alloc, &items[size_active]);
++ }
++
++ __forceinline void clear()
++ {
++ /* destroy elements */
++ for (size_t i=0; i<size_active; i++)
++ std::allocator_traits<decltype(alloc)>::destroy(alloc, &items[i]);
++
++ /* free memory */
++ alloc.deallocate(items,size_alloced);
++ items = nullptr;
++ size_active = size_alloced = 0;
++ }
++
++ /******************** Comparisons **************************/
++
++ friend bool operator== (const vector_t& a, const vector_t& b)
++ {
++ if (a.size() != b.size()) return false;
++ for (size_t i=0; i<a.size(); i++)
++ if (a[i] != b[i])
++ return false;
++ return true;
++ }
++
++ friend bool operator!= (const vector_t& a, const vector_t& b) {
++ return !(a==b);
++ }
++
++ private:
++
++ __forceinline void internal_resize_init(size_t new_active)
++ {
++ assert(size_active == 0);
++ assert(size_alloced == 0);
++ assert(items == nullptr);
++ if (new_active == 0) return;
++ items = alloc.allocate(new_active);
++ for (size_t i=0; i<new_active; i++) ::new (&items[i]) T();
++ size_active = new_active;
++ size_alloced = new_active;
++ }
++
++ __forceinline void internal_resize(size_t new_active, size_t new_alloced)
++ {
++ assert(new_active <= new_alloced);
++
++ /* destroy elements */
++ if (new_active < size_active)
++ {
++ for (size_t i=new_active; i<size_active; i++)
++ std::allocator_traits<decltype(alloc)>::destroy(alloc, &items[i]);
++ size_active = new_active;
++ }
++
++ /* only reallocate if necessary */
++ if (new_alloced == size_alloced) {
++ for (size_t i=size_active; i<new_active; i++) ::new (&items[i]) T;
++ size_active = new_active;
++ return;
++ }
++
++ /* reallocate and copy items */
++ T* old_items = items;
++ items = alloc.allocate(new_alloced);
++ for (size_t i=0; i<size_active; i++) {
++ ::new (&items[i]) T(std::move(old_items[i]));
++ std::allocator_traits<decltype(alloc)>::destroy(alloc, &old_items[i]);
++ }
++
++ for (size_t i=size_active; i<new_active; i++) {
++ ::new (&items[i]) T;
++ }
++
++ alloc.deallocate(old_items,size_alloced);
++ size_active = new_active;
++ size_alloced = new_alloced;
++ }
++
++ __forceinline size_t internal_grow_size(size_t new_alloced)
++ {
++ /* do nothing if container already large enough */
++ if (new_alloced <= size_alloced)
++ return size_alloced;
++
++ /* resize to next power of 2 otherwise */
++ size_t new_size_alloced = size_alloced;
++ while (new_size_alloced < new_alloced) {
++ new_size_alloced = std::max(size_t(1),2*new_size_alloced);
++ }
++ return new_size_alloced;
++ }
++
++ private:
++ allocator alloc;
++ size_t size_active; // number of valid items
++ size_t size_alloced; // number of items allocated
++ T* items; // data array
++ };
++
++ /*! vector class that performs standard allocations */
++ template<typename T>
++ using vector = vector_t<T,std::allocator<T>>;
++
++ /*! vector class that performs aligned allocations */
++ template<typename T>
++ using avector = vector_t<T,aligned_allocator<T,std::alignment_of<T>::value> >;
++
++ /*! vector class that performs OS allocations */
++ template<typename T>
++ using ovector = vector_t<T,os_allocator<T> >;
++ }