util/TerminatedArray: new class
This commit is contained in:
128
src/util/TerminatedArray.hxx
Normal file
128
src/util/TerminatedArray.hxx
Normal file
@@ -0,0 +1,128 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
// author: Max Kellermann <max.kellermann@gmail.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator> // for std::iterator_traits
|
||||
|
||||
/**
|
||||
* A container-like class which allows iterating over an array
|
||||
* terminated by sentinel value. Most commonly, this is an array of
|
||||
* pointers terminated by nullptr, but null-terminated C strings can
|
||||
* also be used.
|
||||
*
|
||||
* @param T the type of an item in the aray
|
||||
* @param Sentinel the sentinel value
|
||||
*/
|
||||
template<typename T, T Sentinel>
|
||||
class TerminatedArray {
|
||||
T *head;
|
||||
|
||||
/**
|
||||
* A special type for the end iterator which is always equal
|
||||
* the iterator that points to the #Sentinel value.
|
||||
*/
|
||||
struct sentinel {
|
||||
using Traits = std::iterator_traits<T *>;
|
||||
|
||||
using iterator_category = typename Traits::iterator_category;
|
||||
using difference_type = typename Traits::difference_type;
|
||||
using value_type = typename Traits::value_type;
|
||||
using pointer = typename Traits::pointer;
|
||||
using reference = typename Traits::reference;
|
||||
};
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
explicit constexpr TerminatedArray(T *_head) noexcept
|
||||
:head(_head) {}
|
||||
|
||||
class iterator {
|
||||
using Traits = std::iterator_traits<T *>;
|
||||
|
||||
T *cursor;
|
||||
|
||||
public:
|
||||
using iterator_category = typename Traits::iterator_category;
|
||||
using difference_type = typename Traits::difference_type;
|
||||
using value_type = typename Traits::value_type;
|
||||
using pointer = typename Traits::pointer;
|
||||
using reference = typename Traits::reference;
|
||||
|
||||
explicit constexpr iterator(T *_cursor) noexcept
|
||||
:cursor(_cursor) {}
|
||||
|
||||
constexpr bool operator==(const iterator &other) const noexcept {
|
||||
return cursor == other.cursor;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const sentinel &) const noexcept {
|
||||
return *cursor == Sentinel;
|
||||
}
|
||||
|
||||
constexpr auto &operator++() noexcept {
|
||||
++cursor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr auto operator++(int) noexcept {
|
||||
auto old = *this;
|
||||
++cursor;
|
||||
return old;
|
||||
}
|
||||
|
||||
constexpr auto &operator+=(difference_type n) noexcept {
|
||||
cursor += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr auto operator+(difference_type n) const noexcept {
|
||||
return iterator{cursor + n};
|
||||
}
|
||||
|
||||
constexpr auto &operator--() noexcept {
|
||||
--cursor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr auto operator--(int) noexcept {
|
||||
auto old = *this;
|
||||
--cursor;
|
||||
return old;
|
||||
}
|
||||
|
||||
constexpr auto &operator-=(difference_type n) noexcept {
|
||||
cursor -= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr auto operator-(difference_type n) const noexcept {
|
||||
return iterator{cursor - n};
|
||||
}
|
||||
|
||||
reference operator*() const noexcept {
|
||||
return *cursor;
|
||||
}
|
||||
|
||||
pointer operator->() const noexcept {
|
||||
return cursor;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr iterator begin() const noexcept {
|
||||
return iterator{head};
|
||||
}
|
||||
|
||||
constexpr sentinel end() const noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr iterator cbegin() const noexcept {
|
||||
return begin();
|
||||
}
|
||||
|
||||
constexpr sentinel cend() const noexcept {
|
||||
return end();
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user