update external headers

This commit is contained in:
Nick Fisher
2022-02-06 13:28:28 +08:00
parent 24d0973129
commit a08f3d95e3
150 changed files with 27445 additions and 14805 deletions

View File

@@ -1,410 +1,411 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_UTILS_FIXEDCAPACITYVECTOR_H
#define TNT_UTILS_FIXEDCAPACITYVECTOR_H
#include <utils/compressed_pair.h>
#include <utils/Panic.h>
#include <algorithm>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include <stddef.h>
#include <stdint.h>
#ifndef NDEBUG
#define FILAMENT_FORCE_CAPACITY_CHECK true
#else
#define FILAMENT_FORCE_CAPACITY_CHECK false
#endif
namespace utils {
/**
* FixedCapacityVector is (almost) a drop-in replacement for std::vector<> except it has a
* fixed capacity decided at runtime. The vector storage is never reallocated unless reserve()
* is called. Operations that add elements to the vector can fail if there is not enough
* capacity.
*
* An empty vector with a given capacity is created with
* FixedCapacityVector<T>::with_capacity( capacity );
*
* NOTE: When passing an initial size into the FixedCapacityVector constructor, default construction
* of the elements is skipped when their construction is trivial. This behavior is different from
* std::vector. e.g., std::vector<int>(4) constructs 4 zeros while FixedCapacityVector<int>(4)
* allocates 4 uninitialized values. Note that zero initialization is easily achieved by passing in
* the optional value argument, e.g. FixedCapacityVector<int>(4, 0) or foo.resize(4, 0).
*/
template<typename T, typename A = std::allocator<T>, bool CapacityCheck = true>
class UTILS_PUBLIC FixedCapacityVector {
public:
using allocator_type = A;
using value_type = T;
using reference = T&;
using const_reference = T const&;
using size_type = uint32_t;
using difference_type = int32_t;
using pointer = T*;
using const_pointer = T const*;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private:
using storage_traits = std::allocator_traits<allocator_type>;
public:
/** returns an empty vector with the specified capacity */
static FixedCapacityVector with_capacity(
size_type capacity, const allocator_type& allocator = allocator_type()) {
return FixedCapacityVector(construct_with_capacity, capacity, allocator);
}
FixedCapacityVector() = default;
explicit FixedCapacityVector(const allocator_type& allocator) noexcept
: mCapacityAllocator({}, allocator) {
}
explicit FixedCapacityVector(size_type size, const allocator_type& allocator = allocator_type())
: mSize(size),
mCapacityAllocator(size, allocator) {
mData = this->allocator().allocate(this->capacity());
construct(begin(), end());
}
FixedCapacityVector(size_type size, const_reference value,
const allocator_type& alloc = allocator_type())
: mSize(size),
mCapacityAllocator(size, alloc) {
mData = this->allocator().allocate(this->capacity());
construct(begin(), end(), value);
}
FixedCapacityVector(FixedCapacityVector const& rhs)
: mSize(rhs.mSize),
mCapacityAllocator(rhs.capacity(),
storage_traits::select_on_container_copy_construction(rhs.allocator())) {
mData = allocator().allocate(capacity());
std::uninitialized_copy(rhs.begin(), rhs.end(), begin());
}
FixedCapacityVector(FixedCapacityVector&& rhs) noexcept {
this->swap(rhs);
}
~FixedCapacityVector() noexcept {
destroy(begin(), end());
allocator().deallocate(data(), capacity());
}
FixedCapacityVector& operator=(FixedCapacityVector const& rhs) {
if (this != &rhs) {
FixedCapacityVector t(rhs);
this->swap(t);
}
return *this;
}
FixedCapacityVector& operator=(FixedCapacityVector&& rhs) noexcept {
this->swap(rhs);
return *this;
}
allocator_type get_allocator() const noexcept {
return mCapacityAllocator.second();
}
// --------------------------------------------------------------------------------------------
iterator begin() noexcept { return data(); }
iterator end() noexcept { return data() + size(); }
const_iterator begin() const noexcept { return data(); }
const_iterator end() const noexcept { return data() + size(); }
reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
const_iterator cbegin() const noexcept { return begin(); }
const_iterator cend() const noexcept { return end(); }
const_reverse_iterator crbegin() const noexcept { return rbegin(); }
const_reverse_iterator crend() const noexcept { return rend(); }
// --------------------------------------------------------------------------------------------
size_type size() const noexcept { return mSize; }
size_type capacity() const noexcept { return mCapacityAllocator.first(); }
bool empty() const noexcept { return size() == 0; }
size_type max_size() const noexcept {
return std::min(storage_traits::max_size(allocator()),
std::numeric_limits<size_type>::max());
}
// --------------------------------------------------------------------------------------------
reference operator[](size_type n) noexcept {
assert(n < size());
return *(begin() + n);
}
const_reference operator[](size_type n) const noexcept {
assert(n < size());
return *(begin() + n);
}
reference front() noexcept { return *begin(); }
const_reference front() const noexcept { return *begin(); }
reference back() noexcept { return *(end() - 1); }
const_reference back() const noexcept { return *(end() - 1); }
value_type* data() noexcept { return mData; }
const value_type* data() const noexcept { return mData; }
// --------------------------------------------------------------------------------------------
void push_back(const_reference v) {
auto pos = assertCapacityForSize(size() + 1);
++mSize;
storage_traits::construct(allocator(), pos, v);
}
void push_back(value_type&& v) {
auto pos = assertCapacityForSize(size() + 1);
++mSize;
storage_traits::construct(allocator(), pos, std::move(v));
}
template<typename ... ARGS>
reference emplace_back(ARGS&& ... args) {
auto pos = assertCapacityForSize(size() + 1);
++mSize;
storage_traits::construct(allocator(), pos, std::forward<ARGS>(args)...);
return *pos;
}
void pop_back() {
assert(!empty());
--mSize;
destroy(end(), end() + 1);
}
iterator insert(const_iterator position, const_reference v) {
if (position == end()) {
push_back(v);
} else {
assertCapacityForSize(size() + 1);
pointer p = const_cast<pointer>(position);
move_range(p, end(), p + 1);
++mSize;
// here we handle inserting an element of this vector!
const_pointer pv = std::addressof(v);
if (p <= pv && pv < end()) {
*p = *(pv + 1);
} else {
*p = v;
}
}
return const_cast<iterator>(position);
}
iterator insert(const_iterator position, value_type&& v) {
if (position == end()) {
push_back(std::move(v));
} else {
assertCapacityForSize(size() + 1);
pointer p = const_cast<pointer>(position);
move_range(p, end(), p + 1);
++mSize;
*p = std::move(v);
}
return const_cast<iterator>(position);
}
iterator erase(const_iterator pos) {
assert(pos != end());
return erase(pos, pos + 1);
}
iterator erase(const_iterator first, const_iterator last) {
assert(first <= last);
auto e = std::move(const_cast<iterator>(last), end(), const_cast<iterator>(first));
destroy(e, end());
mSize -= std::distance(first, last);
return const_cast<iterator>(first);
}
void clear() noexcept {
destroy(begin(), end());
mSize = 0;
}
void resize(size_type count) {
assertCapacityForSize(count);
if constexpr(std::is_trivially_constructible_v<value_type> &&
std::is_trivially_destructible_v<value_type>) {
// we check for triviality here so that the implementation could be non-inline
mSize = count;
} else {
resize_non_trivial(count);
}
}
void resize(size_type count, const_reference v) {
assertCapacityForSize(count);
resize_non_trivial(count, v);
}
void swap(FixedCapacityVector& other) {
using std::swap;
swap(mData, other.mData);
swap(mSize, other.mSize);
mCapacityAllocator.swap(other.mCapacityAllocator);
}
UTILS_NOINLINE
void reserve(size_type c) {
if (c > capacity()) {
FixedCapacityVector t(construct_with_capacity, c, allocator());
t.mSize = size();
std::uninitialized_move(begin(), end(), t.begin());
this->swap(t);
}
}
private:
enum construct_with_capacity_tag{ construct_with_capacity };
FixedCapacityVector(construct_with_capacity_tag,
size_type capacity, const allocator_type& allocator = allocator_type())
: mCapacityAllocator(capacity, allocator) {
mData = this->allocator().allocate(this->capacity());
}
allocator_type& allocator() noexcept {
return mCapacityAllocator.second();
}
allocator_type const& allocator() const noexcept {
return mCapacityAllocator.second();
}
iterator assertCapacityForSize(size_type s) {
if constexpr(CapacityCheck || FILAMENT_FORCE_CAPACITY_CHECK) {
ASSERT_PRECONDITION(capacity() >= s,
"capacity exceeded: requested size %lu, available capacity %lu.",
(unsigned long)s, (unsigned long)capacity());
}
return end();
}
inline void construct(iterator first, iterator last) noexcept {
// we check for triviality here so that the implementation could be non-inline
if constexpr(!std::is_trivially_constructible_v<value_type>) {
construct_non_trivial(first, last);
}
}
void construct(iterator first, iterator last, const_reference proto) noexcept {
#pragma nounroll
while (first != last) {
storage_traits::construct(allocator(), first++, proto);
}
}
// should this be NOINLINE?
void construct_non_trivial(iterator first, iterator last) noexcept {
#pragma nounroll
while (first != last) {
storage_traits::construct(allocator(), first++);
}
}
inline void destroy(iterator first, iterator last) noexcept {
// we check for triviality here so that the implementation could be non-inline
if constexpr(!std::is_trivially_destructible_v<value_type>) {
destroy_non_trivial(first, last);
}
}
// should this be NOINLINE?
void destroy_non_trivial(iterator first, iterator last) noexcept {
#pragma nounroll
while (first != last) {
storage_traits::destroy(allocator(), --last);
}
}
// should this be NOINLINE?
void resize_non_trivial(size_type count) {
if (count > size()) {
construct(end(), begin() + count);
} else if (count < size()) {
destroy(begin() + count, end());
}
mSize = count;
}
// should this be NOINLINE?
void resize_non_trivial(size_type count, const_reference v) {
if (count > size()) {
construct(end(), begin() + count, v);
} else if (count < size()) {
destroy(begin() + count, end());
}
mSize = count;
}
// should this be NOINLINE?
void move_range(pointer s, pointer e, pointer to) {
if constexpr(std::is_trivially_copy_assignable_v<value_type>
&& std::is_trivially_destructible_v<value_type>) {
// this generates memmove -- which doesn't happen otherwise
std::move_backward(s, e, to + std::distance(s, e));
} else {
pointer our_end = end();
difference_type n = our_end - to; // nb of elements to move by operator=
pointer i = s + n; // 1st element to move by move ctor
for (pointer d = our_end ; i < our_end ; ++i, ++d) {
storage_traits::construct(allocator(), d, std::move(*i));
}
std::move_backward(s, s + n, our_end);
}
}
template<typename TYPE>
class SizeTypeWrapper {
TYPE value{};
public:
SizeTypeWrapper() noexcept = default;
SizeTypeWrapper(SizeTypeWrapper const& rhs) noexcept = default;
explicit SizeTypeWrapper(TYPE value) noexcept : value(value) { }
SizeTypeWrapper operator=(TYPE rhs) noexcept { value = rhs; return *this; }
operator TYPE() const noexcept { return value; }
};
pointer mData{};
size_type mSize{};
compressed_pair<SizeTypeWrapper<size_type>, allocator_type> mCapacityAllocator{};
};
} // namespace utils
#endif //TNT_UTILS_FIXEDCAPACITYVECTOR_H
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_UTILS_FIXEDCAPACITYVECTOR_H
#define TNT_UTILS_FIXEDCAPACITYVECTOR_H
#include <utils/compressed_pair.h>
#include <utils/Panic.h>
#include <algorithm>
#include <limits>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include <stddef.h>
#include <stdint.h>
#ifndef NDEBUG
#define FILAMENT_FORCE_CAPACITY_CHECK true
#else
#define FILAMENT_FORCE_CAPACITY_CHECK false
#endif
namespace utils {
/**
* FixedCapacityVector is (almost) a drop-in replacement for std::vector<> except it has a
* fixed capacity decided at runtime. The vector storage is never reallocated unless reserve()
* is called. Operations that add elements to the vector can fail if there is not enough
* capacity.
*
* An empty vector with a given capacity is created with
* FixedCapacityVector<T>::with_capacity( capacity );
*
* NOTE: When passing an initial size into the FixedCapacityVector constructor, default construction
* of the elements is skipped when their construction is trivial. This behavior is different from
* std::vector. e.g., std::vector<int>(4) constructs 4 zeros while FixedCapacityVector<int>(4)
* allocates 4 uninitialized values. Note that zero initialization is easily achieved by passing in
* the optional value argument, e.g. FixedCapacityVector<int>(4, 0) or foo.resize(4, 0).
*/
template<typename T, typename A = std::allocator<T>, bool CapacityCheck = true>
class UTILS_PUBLIC FixedCapacityVector {
public:
using allocator_type = A;
using value_type = T;
using reference = T&;
using const_reference = T const&;
using size_type = uint32_t;
using difference_type = int32_t;
using pointer = T*;
using const_pointer = T const*;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private:
using storage_traits = std::allocator_traits<allocator_type>;
public:
/** returns an empty vector with the specified capacity */
static FixedCapacityVector with_capacity(
size_type capacity, const allocator_type& allocator = allocator_type()) {
return FixedCapacityVector(construct_with_capacity, capacity, allocator);
}
FixedCapacityVector() = default;
explicit FixedCapacityVector(const allocator_type& allocator) noexcept
: mCapacityAllocator({}, allocator) {
}
explicit FixedCapacityVector(size_type size, const allocator_type& allocator = allocator_type())
: mSize(size),
mCapacityAllocator(size, allocator) {
mData = this->allocator().allocate(this->capacity());
construct(begin(), end());
}
FixedCapacityVector(size_type size, const_reference value,
const allocator_type& alloc = allocator_type())
: mSize(size),
mCapacityAllocator(size, alloc) {
mData = this->allocator().allocate(this->capacity());
construct(begin(), end(), value);
}
FixedCapacityVector(FixedCapacityVector const& rhs)
: mSize(rhs.mSize),
mCapacityAllocator(rhs.capacity(),
storage_traits::select_on_container_copy_construction(rhs.allocator())) {
mData = allocator().allocate(capacity());
std::uninitialized_copy(rhs.begin(), rhs.end(), begin());
}
FixedCapacityVector(FixedCapacityVector&& rhs) noexcept {
this->swap(rhs);
}
~FixedCapacityVector() noexcept {
destroy(begin(), end());
allocator().deallocate(data(), capacity());
}
FixedCapacityVector& operator=(FixedCapacityVector const& rhs) {
if (this != &rhs) {
FixedCapacityVector t(rhs);
this->swap(t);
}
return *this;
}
FixedCapacityVector& operator=(FixedCapacityVector&& rhs) noexcept {
this->swap(rhs);
return *this;
}
allocator_type get_allocator() const noexcept {
return mCapacityAllocator.second();
}
// --------------------------------------------------------------------------------------------
iterator begin() noexcept { return data(); }
iterator end() noexcept { return data() + size(); }
const_iterator begin() const noexcept { return data(); }
const_iterator end() const noexcept { return data() + size(); }
reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
const_iterator cbegin() const noexcept { return begin(); }
const_iterator cend() const noexcept { return end(); }
const_reverse_iterator crbegin() const noexcept { return rbegin(); }
const_reverse_iterator crend() const noexcept { return rend(); }
// --------------------------------------------------------------------------------------------
size_type size() const noexcept { return mSize; }
size_type capacity() const noexcept { return mCapacityAllocator.first(); }
bool empty() const noexcept { return size() == 0; }
size_type max_size() const noexcept {
return std::min(storage_traits::max_size(allocator()),
std::numeric_limits<size_type>::max());
}
// --------------------------------------------------------------------------------------------
reference operator[](size_type n) noexcept {
assert(n < size());
return *(begin() + n);
}
const_reference operator[](size_type n) const noexcept {
assert(n < size());
return *(begin() + n);
}
reference front() noexcept { return *begin(); }
const_reference front() const noexcept { return *begin(); }
reference back() noexcept { return *(end() - 1); }
const_reference back() const noexcept { return *(end() - 1); }
value_type* data() noexcept { return mData; }
const value_type* data() const noexcept { return mData; }
// --------------------------------------------------------------------------------------------
void push_back(const_reference v) {
auto pos = assertCapacityForSize(size() + 1);
++mSize;
storage_traits::construct(allocator(), pos, v);
}
void push_back(value_type&& v) {
auto pos = assertCapacityForSize(size() + 1);
++mSize;
storage_traits::construct(allocator(), pos, std::move(v));
}
template<typename ... ARGS>
reference emplace_back(ARGS&& ... args) {
auto pos = assertCapacityForSize(size() + 1);
++mSize;
storage_traits::construct(allocator(), pos, std::forward<ARGS>(args)...);
return *pos;
}
void pop_back() {
assert(!empty());
--mSize;
destroy(end(), end() + 1);
}
iterator insert(const_iterator position, const_reference v) {
if (position == end()) {
push_back(v);
} else {
assertCapacityForSize(size() + 1);
pointer p = const_cast<pointer>(position);
move_range(p, end(), p + 1);
++mSize;
// here we handle inserting an element of this vector!
const_pointer pv = std::addressof(v);
if (p <= pv && pv < end()) {
*p = *(pv + 1);
} else {
*p = v;
}
}
return const_cast<iterator>(position);
}
iterator insert(const_iterator position, value_type&& v) {
if (position == end()) {
push_back(std::move(v));
} else {
assertCapacityForSize(size() + 1);
pointer p = const_cast<pointer>(position);
move_range(p, end(), p + 1);
++mSize;
*p = std::move(v);
}
return const_cast<iterator>(position);
}
iterator erase(const_iterator pos) {
assert(pos != end());
return erase(pos, pos + 1);
}
iterator erase(const_iterator first, const_iterator last) {
assert(first <= last);
auto e = std::move(const_cast<iterator>(last), end(), const_cast<iterator>(first));
destroy(e, end());
mSize -= std::distance(first, last);
return const_cast<iterator>(first);
}
void clear() noexcept {
destroy(begin(), end());
mSize = 0;
}
void resize(size_type count) {
assertCapacityForSize(count);
if constexpr(std::is_trivially_constructible_v<value_type> &&
std::is_trivially_destructible_v<value_type>) {
// we check for triviality here so that the implementation could be non-inline
mSize = count;
} else {
resize_non_trivial(count);
}
}
void resize(size_type count, const_reference v) {
assertCapacityForSize(count);
resize_non_trivial(count, v);
}
void swap(FixedCapacityVector& other) {
using std::swap;
swap(mData, other.mData);
swap(mSize, other.mSize);
mCapacityAllocator.swap(other.mCapacityAllocator);
}
UTILS_NOINLINE
void reserve(size_type c) {
if (c > capacity()) {
FixedCapacityVector t(construct_with_capacity, c, allocator());
t.mSize = size();
std::uninitialized_move(begin(), end(), t.begin());
this->swap(t);
}
}
private:
enum construct_with_capacity_tag{ construct_with_capacity };
FixedCapacityVector(construct_with_capacity_tag,
size_type capacity, const allocator_type& allocator = allocator_type())
: mCapacityAllocator(capacity, allocator) {
mData = this->allocator().allocate(this->capacity());
}
allocator_type& allocator() noexcept {
return mCapacityAllocator.second();
}
allocator_type const& allocator() const noexcept {
return mCapacityAllocator.second();
}
iterator assertCapacityForSize(size_type s) {
if constexpr(CapacityCheck || FILAMENT_FORCE_CAPACITY_CHECK) {
ASSERT_PRECONDITION(capacity() >= s,
"capacity exceeded: requested size %lu, available capacity %lu.",
(unsigned long)s, (unsigned long)capacity());
}
return end();
}
inline void construct(iterator first, iterator last) noexcept {
// we check for triviality here so that the implementation could be non-inline
if constexpr(!std::is_trivially_constructible_v<value_type>) {
construct_non_trivial(first, last);
}
}
void construct(iterator first, iterator last, const_reference proto) noexcept {
#pragma nounroll
while (first != last) {
storage_traits::construct(allocator(), first++, proto);
}
}
// should this be NOINLINE?
void construct_non_trivial(iterator first, iterator last) noexcept {
#pragma nounroll
while (first != last) {
storage_traits::construct(allocator(), first++);
}
}
inline void destroy(iterator first, iterator last) noexcept {
// we check for triviality here so that the implementation could be non-inline
if constexpr(!std::is_trivially_destructible_v<value_type>) {
destroy_non_trivial(first, last);
}
}
// should this be NOINLINE?
void destroy_non_trivial(iterator first, iterator last) noexcept {
#pragma nounroll
while (first != last) {
storage_traits::destroy(allocator(), --last);
}
}
// should this be NOINLINE?
void resize_non_trivial(size_type count) {
if (count > size()) {
construct(end(), begin() + count);
} else if (count < size()) {
destroy(begin() + count, end());
}
mSize = count;
}
// should this be NOINLINE?
void resize_non_trivial(size_type count, const_reference v) {
if (count > size()) {
construct(end(), begin() + count, v);
} else if (count < size()) {
destroy(begin() + count, end());
}
mSize = count;
}
// should this be NOINLINE?
void move_range(pointer s, pointer e, pointer to) {
if constexpr(std::is_trivially_copy_assignable_v<value_type>
&& std::is_trivially_destructible_v<value_type>) {
// this generates memmove -- which doesn't happen otherwise
std::move_backward(s, e, to + std::distance(s, e));
} else {
pointer our_end = end();
difference_type n = our_end - to; // nb of elements to move by operator=
pointer i = s + n; // 1st element to move by move ctor
for (pointer d = our_end ; i < our_end ; ++i, ++d) {
storage_traits::construct(allocator(), d, std::move(*i));
}
std::move_backward(s, s + n, our_end);
}
}
template<typename TYPE>
class SizeTypeWrapper {
TYPE value{};
public:
SizeTypeWrapper() noexcept = default;
SizeTypeWrapper(SizeTypeWrapper const& rhs) noexcept = default;
explicit SizeTypeWrapper(TYPE value) noexcept : value(value) { }
SizeTypeWrapper operator=(TYPE rhs) noexcept { value = rhs; return *this; }
operator TYPE() const noexcept { return value; }
};
pointer mData{};
size_type mSize{};
compressed_pair<SizeTypeWrapper<size_type>, allocator_type> mCapacityAllocator{};
};
} // namespace utils
#endif // TNT_UTILS_FIXEDCAPACITYVECTOR_H