blob: cad37f52655f6c32690a9352f67188dd0ef68012 [file] [log] [blame]
/* Copyright (c) 2015-2025 The Khronos Group Inc.
* Copyright (c) 2015-2025 Valve Corporation
* Copyright (c) 2015-2025 LunarG, Inc.
*
* 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.
*/
#pragma once
#include <cstddef>
#include <type_traits>
#include <utility>
namespace vvl {
// Partial implementation of std::span for C++11
template <typename T, typename Iterator>
class enumeration {
public:
using pointer = T *;
using const_pointer = T const *;
using iterator = Iterator;
using const_iterator = const Iterator;
enumeration() = default;
enumeration(pointer start, size_t n) : data_(start), count_(n) {}
template <typename Position>
enumeration(Position start, Position end) : data_(&(*start)), count_(end - start) {}
template <typename Container>
enumeration(Container &c) : data_(c.data()), count_(c.size()) {}
iterator begin() { return data_; }
const_iterator begin() const { return data_; }
iterator end() { return data_ + count_; }
const_iterator end() const { return data_ + count_; }
T &operator[](size_t i) { return data_[i]; }
const T &operator[](size_t i) const { return data_[i]; }
T &front() { return *data_; }
const T &front() const { return *data_; }
T &back() { return *(data_ + (count_ - 1)); }
const T &back() const { return *(data_ + (count_ - 1)); }
size_t size() const { return count_; }
bool empty() const { return count_ == 0; }
pointer data() const { return data_; }
private:
pointer data_ = {};
size_t count_ = 0;
};
template <typename T, typename IndexType = size_t>
class IndexedIterator {
public:
IndexedIterator(T *data, IndexType index = 0) : index_(index), data_(data) {}
std::pair<IndexType, T &> operator*() { return std::pair<IndexType, T &>(index_, *data_); }
std::pair<IndexType, T> operator*() const { return std::make_pair(index_, *data_); }
// prefix increment
IndexedIterator<T, IndexType> &operator++() {
++data_;
++index_;
return *this;
}
// postfix increment
IndexedIterator<T, IndexType> operator++(int) {
IndexedIterator<T, IndexType> old = *this;
operator++();
return old;
}
bool operator==(const IndexedIterator<T, IndexType> &rhs) const {
// No need to compare indices, just compare pointers
// And given the implementation of enumeration::end(),
// where no index is given when constructing an iterator,
// index_ will default to 0 for end(), which is wrong, but we can live with it for now
return data_ == rhs.data_;
}
bool operator!=(const IndexedIterator<T, IndexType> &rhs) const { return data_ != rhs.data_; }
public:
IndexType index_ = 0;
T *data_;
};
template <typename T>
using span = enumeration<T, T *>;
//
// Allow type inference that using the constructor doesn't allow in C++11
template <typename T>
span<T> make_span(T *begin, size_t count) {
return span<T>(begin, count);
}
template <typename T>
span<T> make_span(T *begin, T *end) {
return make_span<T>(begin, end);
}
template <typename Container>
auto make_span(Container &container) {
return span<typename Container::value_type>(container.data(), container.size());
}
template <typename Container>
auto make_span(const Container &container) {
return span<std::add_const_t<typename Container::value_type>>(container.data(), container.size());
}
template <typename T, typename IndexType>
auto enumerate(T *begin, IndexType count) {
return enumeration<T, IndexedIterator<T, IndexType>>(begin, count);
}
template <typename T>
auto enumerate(T *begin, T *end) {
return enumeration<T, IndexedIterator<T>>(begin, end);
}
template <typename Container>
auto enumerate(Container &container) {
return enumeration<typename Container::value_type,
IndexedIterator<typename Container::value_type, typename Container::size_type>>(container.data(),
container.size());
}
template <typename Container>
auto enumerate(const Container &container) {
return enumeration<std::add_const_t<typename Container::value_type>,
IndexedIterator<std::add_const_t<typename Container::value_type>, typename Container::size_type>>(
container.data(), container.size());
}
} // namespace vvl