486 lines
14 KiB
C++
486 lines
14 KiB
C++
/*
|
|
* Copyright (C) 2018-2024 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "shared/source/helpers/debug_helpers.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <limits>
|
|
#include <tuple>
|
|
#include <vector>
|
|
|
|
template <size_t onStackCapacity>
|
|
struct StackVecSize {
|
|
static constexpr size_t max32 = std::numeric_limits<uint32_t>::max();
|
|
static constexpr size_t max16 = std::numeric_limits<uint16_t>::max();
|
|
static constexpr size_t max8 = std::numeric_limits<uint8_t>::max();
|
|
|
|
using SizeT = std::conditional_t<(onStackCapacity < max8), uint8_t,
|
|
std::conditional_t<(onStackCapacity < max16), uint16_t,
|
|
std::conditional_t<(onStackCapacity < max32), uint32_t, size_t>>>;
|
|
};
|
|
|
|
template <typename DataType, size_t onStackCapacity,
|
|
typename StackSizeT = typename StackVecSize<onStackCapacity>::SizeT>
|
|
class StackVec { // NOLINT(clang-analyzer-optin.performance.Padding)
|
|
public:
|
|
using value_type = DataType; // NOLINT(readability-identifier-naming)
|
|
using SizeT = StackSizeT;
|
|
using iterator = DataType *; // NOLINT(readability-identifier-naming)
|
|
using const_iterator = const DataType *; // NOLINT(readability-identifier-naming)
|
|
using reverse_iterator = std::reverse_iterator<iterator>; // NOLINT(readability-identifier-naming)
|
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>; // NOLINT(readability-identifier-naming)
|
|
|
|
static constexpr SizeT onStackCaps = onStackCapacity;
|
|
|
|
StackVec() {
|
|
switchToStackMem();
|
|
}
|
|
|
|
template <typename ItType>
|
|
StackVec(ItType beginIt, ItType endIt) {
|
|
switchToStackMem();
|
|
size_t count = (endIt - beginIt);
|
|
if (count > onStackCapacity) {
|
|
dynamicMem = new std::vector<DataType>(beginIt, endIt);
|
|
return;
|
|
}
|
|
|
|
while (beginIt != endIt) {
|
|
push_back(*beginIt);
|
|
++beginIt;
|
|
}
|
|
onStackSize = static_cast<SizeT>(count);
|
|
}
|
|
|
|
StackVec(const StackVec &rhs) {
|
|
switchToStackMem();
|
|
if (onStackCaps < rhs.size()) {
|
|
dynamicMem = new std::vector<DataType>(rhs.begin(), rhs.end());
|
|
return;
|
|
}
|
|
|
|
for (const auto &v : rhs) {
|
|
push_back(v);
|
|
}
|
|
}
|
|
|
|
explicit StackVec(size_t initialSize)
|
|
: StackVec() {
|
|
switchToStackMem();
|
|
resize(initialSize);
|
|
}
|
|
|
|
StackVec(std::initializer_list<DataType> init) {
|
|
switchToStackMem();
|
|
reserve(init.size());
|
|
for (const auto &obj : init) {
|
|
push_back(obj);
|
|
}
|
|
}
|
|
|
|
StackVec &operator=(const StackVec &rhs) {
|
|
if (this == &rhs) {
|
|
return *this;
|
|
}
|
|
clear();
|
|
|
|
if (usesDynamicMem()) {
|
|
this->dynamicMem->assign(rhs.begin(), rhs.end());
|
|
return *this;
|
|
}
|
|
|
|
if (onStackCaps < rhs.size()) {
|
|
this->dynamicMem = new std::vector<DataType>(rhs.begin(), rhs.end());
|
|
return *this;
|
|
}
|
|
|
|
for (const auto &v : rhs) {
|
|
push_back(v);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
StackVec(StackVec &&rhs) {
|
|
onStackMem = reinterpret_cast<DataType *const>(onStackMemRawBytes);
|
|
if (rhs.usesDynamicMem()) {
|
|
this->dynamicMem = rhs.dynamicMem;
|
|
rhs.switchToStackMem();
|
|
return;
|
|
}
|
|
|
|
for (const auto &v : rhs) {
|
|
push_back(v);
|
|
}
|
|
rhs.clear();
|
|
}
|
|
|
|
StackVec &operator=(StackVec &&rhs) {
|
|
if (this == &rhs) {
|
|
return *this;
|
|
}
|
|
|
|
clear();
|
|
|
|
if (rhs.usesDynamicMem()) {
|
|
if (usesDynamicMem()) {
|
|
delete this->dynamicMem;
|
|
}
|
|
this->dynamicMem = rhs.dynamicMem;
|
|
rhs.switchToStackMem();
|
|
return *this;
|
|
}
|
|
|
|
if (usesDynamicMem()) {
|
|
this->dynamicMem->assign(rhs.begin(), rhs.end());
|
|
return *this;
|
|
}
|
|
|
|
for (const auto &v : rhs) {
|
|
push_back(v);
|
|
}
|
|
rhs.clear();
|
|
|
|
return *this;
|
|
}
|
|
|
|
template <typename RhsT>
|
|
void swap(RhsT &rhs) {
|
|
if (this->usesDynamicMem() && rhs.usesDynamicMem()) {
|
|
this->dynamicMem->swap(*rhs.dynamicMem);
|
|
return;
|
|
}
|
|
size_t smallerSize = this->size() < rhs.size() ? this->size() : rhs.size();
|
|
size_t i = 0;
|
|
for (; i < smallerSize; ++i) {
|
|
std::swap((*this)[i], rhs[i]);
|
|
}
|
|
if (this->size() == smallerSize) {
|
|
auto biggerSize = rhs.size();
|
|
for (; i < biggerSize; ++i) {
|
|
this->push_back(std::move(rhs[i]));
|
|
}
|
|
rhs.resize(smallerSize);
|
|
} else {
|
|
auto biggerSize = this->size();
|
|
for (; i < biggerSize; ++i) {
|
|
rhs.push_back(std::move((*this)[i]));
|
|
}
|
|
this->resize(smallerSize);
|
|
}
|
|
}
|
|
|
|
~StackVec() {
|
|
if (usesDynamicMem()) {
|
|
delete dynamicMem;
|
|
return;
|
|
}
|
|
clearStackObjects();
|
|
}
|
|
|
|
size_t size() const {
|
|
if (usesDynamicMem()) {
|
|
return dynamicMem->size();
|
|
}
|
|
return onStackSize;
|
|
}
|
|
|
|
bool empty() const {
|
|
return 0U == size();
|
|
}
|
|
|
|
size_t capacity() const {
|
|
if (usesDynamicMem()) {
|
|
return dynamicMem->capacity();
|
|
}
|
|
return onStackCapacity;
|
|
}
|
|
|
|
void reserve(size_t newCapacity) {
|
|
if (newCapacity > onStackCaps) {
|
|
ensureDynamicMem();
|
|
dynamicMem->reserve(newCapacity);
|
|
}
|
|
}
|
|
|
|
void clear() {
|
|
if (usesDynamicMem()) {
|
|
dynamicMem->clear();
|
|
return;
|
|
}
|
|
clearStackObjects();
|
|
}
|
|
|
|
void push_back(const DataType &v) { // NOLINT(readability-identifier-naming)
|
|
isDynamicMemNeeded();
|
|
|
|
if (usesDynamicMem()) {
|
|
dynamicMem->push_back(v);
|
|
return;
|
|
}
|
|
|
|
new (reinterpret_cast<DataType *>(onStackMemRawBytes) + onStackSize) DataType(v);
|
|
++onStackSize;
|
|
}
|
|
|
|
void push_back(DataType &&v) { // NOLINT(readability-identifier-naming)
|
|
isDynamicMemNeeded();
|
|
|
|
if (usesDynamicMem()) {
|
|
dynamicMem->push_back(std::move(v));
|
|
return;
|
|
}
|
|
|
|
new (reinterpret_cast<DataType *>(onStackMemRawBytes) + onStackSize) DataType(std::move(v));
|
|
++onStackSize;
|
|
}
|
|
|
|
void pop_back() { // NOLINT(readability-identifier-naming)
|
|
if (usesDynamicMem()) {
|
|
dynamicMem->pop_back();
|
|
return;
|
|
}
|
|
|
|
UNRECOVERABLE_IF(0 == onStackSize);
|
|
|
|
clearStackObjects(onStackSize - 1, 1U);
|
|
--onStackSize;
|
|
}
|
|
|
|
DataType &operator[](std::size_t idx) {
|
|
if (usesDynamicMem()) {
|
|
return (*dynamicMem)[idx];
|
|
}
|
|
return *(reinterpret_cast<DataType *>(onStackMemRawBytes) + idx);
|
|
}
|
|
|
|
DataType &at(std::size_t idx) { return this->operator[](idx); }
|
|
|
|
const DataType &at(std::size_t idx) const { return this->operator[](idx); }
|
|
|
|
const DataType &operator[](std::size_t idx) const {
|
|
if (usesDynamicMem()) {
|
|
return (*dynamicMem)[idx];
|
|
}
|
|
return *(reinterpret_cast<const DataType *>(onStackMemRawBytes) + idx);
|
|
}
|
|
|
|
iterator begin() {
|
|
if (usesDynamicMem()) {
|
|
return dynamicMem->data();
|
|
}
|
|
|
|
return reinterpret_cast<DataType *>(onStackMemRawBytes);
|
|
}
|
|
|
|
reverse_iterator rbegin() {
|
|
return reverse_iterator(end());
|
|
}
|
|
|
|
const_reverse_iterator crbegin() const {
|
|
return const_reverse_iterator(end());
|
|
}
|
|
|
|
const_iterator begin() const {
|
|
if (usesDynamicMem()) {
|
|
return dynamicMem->data();
|
|
}
|
|
|
|
return reinterpret_cast<const DataType *>(onStackMemRawBytes);
|
|
}
|
|
|
|
iterator end() {
|
|
if (usesDynamicMem()) {
|
|
return dynamicMem->data() + dynamicMem->size();
|
|
}
|
|
|
|
return reinterpret_cast<DataType *>(onStackMemRawBytes) + onStackSize;
|
|
}
|
|
|
|
reverse_iterator rend() {
|
|
return reverse_iterator(begin());
|
|
}
|
|
|
|
const_reverse_iterator crend() const {
|
|
return const_reverse_iterator(begin());
|
|
}
|
|
|
|
const_iterator end() const {
|
|
if (usesDynamicMem()) {
|
|
return dynamicMem->data() + dynamicMem->size();
|
|
}
|
|
|
|
return reinterpret_cast<const DataType *>(onStackMemRawBytes) + onStackSize;
|
|
}
|
|
|
|
void resize(size_t newSize) {
|
|
this->resizeImpl(newSize, nullptr);
|
|
}
|
|
|
|
void resize(size_t newSize, const DataType &value) {
|
|
resizeImpl(newSize, &value);
|
|
}
|
|
|
|
bool usesDynamicMem() const {
|
|
return reinterpret_cast<uintptr_t>(this->onStackMem) != reinterpret_cast<uintptr_t>(onStackMemRawBytes) && this->dynamicMem;
|
|
}
|
|
|
|
auto data() {
|
|
if (usesDynamicMem()) {
|
|
return dynamicMem->data();
|
|
}
|
|
return reinterpret_cast<DataType *>(onStackMemRawBytes);
|
|
}
|
|
|
|
private:
|
|
template <typename RhsDataType, size_t rhsOnStackCapacity, typename RhsStackSizeT>
|
|
friend class StackVec;
|
|
|
|
void resizeImpl(size_t newSize, const DataType *value) {
|
|
// new size does not fit into internal mem
|
|
if (newSize > onStackCaps) {
|
|
ensureDynamicMem();
|
|
}
|
|
|
|
// memory already backed by stl vector
|
|
if (usesDynamicMem()) {
|
|
if (value != nullptr) {
|
|
dynamicMem->resize(newSize, *value);
|
|
} else {
|
|
dynamicMem->resize(newSize);
|
|
}
|
|
return;
|
|
}
|
|
|
|
auto currentSize = std::min(onStackSize, onStackCaps);
|
|
if (newSize <= currentSize) {
|
|
// trim elements
|
|
clearStackObjects(newSize, currentSize - newSize);
|
|
onStackSize = static_cast<SizeT>(newSize);
|
|
return;
|
|
}
|
|
|
|
// add new elements
|
|
if (value != nullptr) {
|
|
// copy-construct elements
|
|
while (onStackSize < newSize) {
|
|
new (reinterpret_cast<DataType *>(onStackMemRawBytes) + onStackSize) DataType(*value);
|
|
++onStackSize;
|
|
}
|
|
} else {
|
|
// default-construct elements
|
|
while (onStackSize < newSize) {
|
|
new (reinterpret_cast<DataType *>(onStackMemRawBytes) + onStackSize) DataType();
|
|
++onStackSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
void isDynamicMemNeeded() {
|
|
if (onStackSize == onStackCaps) {
|
|
ensureDynamicMem();
|
|
}
|
|
}
|
|
|
|
void ensureDynamicMem() {
|
|
if (usesDynamicMem()) {
|
|
return;
|
|
}
|
|
dynamicMem = new std::vector<DataType>();
|
|
if (onStackSize > 0) {
|
|
dynamicMem->reserve(onStackSize);
|
|
for (auto it = reinterpret_cast<DataType *>(onStackMemRawBytes), end = reinterpret_cast<DataType *>(onStackMemRawBytes) + onStackSize; it != end; ++it) {
|
|
dynamicMem->push_back(std::move(*it));
|
|
}
|
|
clearStackObjects();
|
|
}
|
|
}
|
|
|
|
void clearStackObjects() {
|
|
clearStackObjects(0, onStackSize);
|
|
onStackSize = 0;
|
|
}
|
|
|
|
void clearStackObjects(size_t offset, size_t count) {
|
|
UNRECOVERABLE_IF(offset + count > onStackSize);
|
|
for (auto it = reinterpret_cast<DataType *>(onStackMemRawBytes) + offset, end = reinterpret_cast<DataType *>(onStackMemRawBytes) + offset + count; it != end; ++it) {
|
|
it->~DataType();
|
|
}
|
|
}
|
|
void switchToStackMem() {
|
|
onStackMem = reinterpret_cast<DataType *const>(onStackMemRawBytes);
|
|
}
|
|
|
|
union {
|
|
std::vector<DataType> *dynamicMem;
|
|
DataType *onStackMem;
|
|
};
|
|
|
|
alignas(alignof(DataType)) char onStackMemRawBytes[sizeof(DataType[onStackCaps])];
|
|
SizeT onStackSize = 0U;
|
|
};
|
|
|
|
namespace {
|
|
static_assert(sizeof(StackVec<char, 1U>::SizeT) == 1u, "");
|
|
static_assert(sizeof(StackVec<char, 7U>) <= 16u, "");
|
|
static_assert(sizeof(StackVec<uint32_t, 3U>) <= 24u, "");
|
|
} // namespace
|
|
|
|
template <typename T, size_t lhsStackCaps, size_t rhsStackCaps>
|
|
bool operator==(const StackVec<T, lhsStackCaps> &lhs,
|
|
const StackVec<T, rhsStackCaps> &rhs) {
|
|
if (lhs.size() != rhs.size()) {
|
|
return false;
|
|
}
|
|
|
|
auto lhsIt = lhs.begin();
|
|
auto lhsEnd = lhs.end();
|
|
auto rhsIt = rhs.begin();
|
|
|
|
for (; lhsIt != lhsEnd; ++lhsIt, ++rhsIt) {
|
|
if (*lhsIt != *rhsIt) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename T, size_t lhsStackCaps, size_t rhsStackCaps>
|
|
bool operator!=(const StackVec<T, lhsStackCaps> &lhs,
|
|
const StackVec<T, rhsStackCaps> &rhs) {
|
|
return false == (lhs == rhs);
|
|
}
|
|
|
|
constexpr size_t maxRootDeviceIndices = 16;
|
|
class RootDeviceIndicesContainer : protected StackVec<uint32_t, maxRootDeviceIndices> {
|
|
public:
|
|
using StackVec<uint32_t, maxRootDeviceIndices>::StackVec;
|
|
using StackVec<uint32_t, maxRootDeviceIndices>::at;
|
|
using StackVec<uint32_t, maxRootDeviceIndices>::begin;
|
|
using StackVec<uint32_t, maxRootDeviceIndices>::end;
|
|
using StackVec<uint32_t, maxRootDeviceIndices>::size;
|
|
using StackVec<uint32_t, maxRootDeviceIndices>::operator[];
|
|
|
|
inline void pushUnique(uint32_t rootDeviceIndex) {
|
|
if (indexPresent.size() <= rootDeviceIndex) {
|
|
indexPresent.resize(rootDeviceIndex + 1);
|
|
}
|
|
if (!indexPresent[rootDeviceIndex]) {
|
|
push_back(rootDeviceIndex);
|
|
indexPresent[rootDeviceIndex] = 1;
|
|
}
|
|
}
|
|
|
|
protected:
|
|
StackVec<int8_t, maxRootDeviceIndices> indexPresent;
|
|
};
|
|
using RootDeviceIndicesMap = StackVec<std::tuple<uint32_t, uint32_t>, maxRootDeviceIndices>;
|