-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
OptionalRef and OptionalArray (#541)
* OptionalRef * Using OptionalRef * Refactoring EnumMap to use OptionalRef * Revert EnumMap changes * More OptionalRef tests * OptionalArray * Apply clang-format * Trying to fix missing include * More includes * Trying to bring back macos CI tests * Fixing clang-tidy --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
- Loading branch information
1 parent
c3ddb33
commit e4d6a5b
Showing
12 changed files
with
462 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
modules/common/chowdsp_data_structures/Structures/chowdsp_OptionalArray.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
#pragma once | ||
|
||
namespace chowdsp | ||
{ | ||
/** | ||
* A data structure similar to std::array<std::optional<T>, N>, but with less memory overhead. | ||
* | ||
* This implementation is still a work-in-progress. | ||
*/ | ||
template <typename T, size_t N> | ||
class OptionalArray | ||
{ | ||
std::array<RawObject<T>, N> objects {}; | ||
std::bitset<N> optional_flags {}; | ||
|
||
public: | ||
using value_type = T; | ||
static constexpr auto max_size = N; | ||
|
||
OptionalArray() = default; | ||
OptionalArray (const OptionalArray&) = default; | ||
OptionalArray& operator= (const OptionalArray&) = default; | ||
OptionalArray (OptionalArray&&) noexcept = default; | ||
OptionalArray& operator= (OptionalArray&&) noexcept = default; | ||
|
||
~OptionalArray() | ||
{ | ||
for (auto [idx, object] : enumerate (objects)) | ||
{ | ||
if (optional_flags[idx]) | ||
object.destruct(); | ||
} | ||
} | ||
|
||
[[nodiscard]] bool has_value (size_t idx) const noexcept | ||
{ | ||
return optional_flags[idx]; | ||
} | ||
|
||
[[nodiscard]] bool empty() const noexcept | ||
{ | ||
return optional_flags.none(); | ||
} | ||
|
||
[[nodiscard]] size_t count_values() const noexcept | ||
{ | ||
return optional_flags.count(); | ||
} | ||
|
||
OptionalRef<T> operator[] (size_t idx) | ||
{ | ||
if (! optional_flags[idx]) | ||
return {}; | ||
return objects[idx].item(); | ||
} | ||
|
||
OptionalRef<const T> operator[] (size_t idx) const | ||
{ | ||
if (! optional_flags[idx]) | ||
return {}; | ||
return objects[idx].item(); | ||
} | ||
|
||
template <typename... Args> | ||
T& emplace (size_t idx, Args&&... args) | ||
{ | ||
if (optional_flags[idx]) | ||
objects[idx].destruct(); | ||
optional_flags[idx] = true; | ||
return *objects[idx].construct (std::forward<Args> (args)...); | ||
} | ||
|
||
void erase (size_t idx) | ||
{ | ||
if (optional_flags[idx]) | ||
{ | ||
objects[idx].destruct(); | ||
optional_flags[idx] = false; | ||
} | ||
} | ||
|
||
template <bool is_const = false> | ||
struct iterator | ||
{ | ||
size_t index {}; | ||
std::conditional_t<is_const, const OptionalArray&, OptionalArray&> array {}; | ||
|
||
bool operator!= (const iterator& other) const noexcept | ||
{ | ||
return &array != &other.array || index != other.index; | ||
} | ||
void operator++() noexcept | ||
{ | ||
do | ||
{ | ||
++index; | ||
} while (index < N && ! array.optional_flags[index]); | ||
} | ||
auto& operator*() const noexcept | ||
{ | ||
return array.objects[index].item(); | ||
} | ||
}; | ||
|
||
auto begin() | ||
{ | ||
return iterator<> { 0, *this }; | ||
} | ||
|
||
auto end() | ||
{ | ||
return iterator<> { N, *this }; | ||
} | ||
|
||
auto begin() const | ||
{ | ||
return cbegin(); | ||
} | ||
|
||
auto end() const | ||
{ | ||
return cend(); | ||
} | ||
|
||
auto cbegin() const | ||
{ | ||
return iterator<true> { 0, *this }; | ||
} | ||
|
||
auto cend() const | ||
{ | ||
return iterator<true> { N, *this }; | ||
} | ||
}; | ||
} // namespace chowdsp |
141 changes: 141 additions & 0 deletions
141
modules/common/chowdsp_data_structures/Structures/chowdsp_OptionalRef.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
#pragma once | ||
|
||
namespace chowdsp | ||
{ | ||
/** | ||
* This class is basically an implementation of std::optional<T&>. | ||
* Under the hood, it's basically just a pointer but with an | ||
* optional-like interface. | ||
* | ||
* Make sure that an OptionalRef never holds on to a reference | ||
* past the lifetime of the referenced object. | ||
*/ | ||
template <typename T> | ||
class OptionalRef | ||
{ | ||
T* ptr = nullptr; | ||
|
||
public: | ||
OptionalRef() = default; | ||
OptionalRef (const OptionalRef&) = default; | ||
OptionalRef& operator= (const OptionalRef&) = default; | ||
OptionalRef (OptionalRef&&) noexcept = default; | ||
OptionalRef& operator= (OptionalRef&&) noexcept = default; | ||
|
||
OptionalRef (std::nullopt_t) // NOLINT(google-explicit-constructor) | ||
{ | ||
} | ||
|
||
OptionalRef (T& value) // NOLINT(google-explicit-constructor) | ||
: ptr { &value } | ||
{ | ||
} | ||
|
||
OptionalRef& operator= (std::nullopt_t) noexcept // NOLINT | ||
{ | ||
ptr = nullptr; | ||
return *this; | ||
} | ||
|
||
OptionalRef& operator= (T& value) noexcept // NOLINT | ||
{ | ||
ptr = &value; | ||
return *this; | ||
} | ||
|
||
T* operator->() noexcept { return ptr; } | ||
const T* operator->() const noexcept { return ptr; } | ||
T& operator*() noexcept { return *ptr; } | ||
const T& operator*() const noexcept { return *ptr; } | ||
|
||
[[nodiscard]] explicit operator bool() const noexcept { return has_value(); } | ||
[[nodiscard]] bool has_value() const noexcept { return ptr != nullptr; } | ||
|
||
T& value() | ||
{ | ||
if (! has_value()) | ||
throw std::bad_optional_access(); | ||
return *ptr; | ||
} | ||
|
||
const T& value() const | ||
{ | ||
if (! has_value()) | ||
throw std::bad_optional_access(); | ||
return *ptr; | ||
} | ||
|
||
void reset() noexcept { ptr = nullptr; } | ||
void swap (OptionalRef& other) noexcept { std::swap (ptr, other.ptr); } | ||
|
||
const T& value_or (const T& other) const { return has_value() ? *ptr : other; } | ||
}; | ||
|
||
template <typename T> | ||
bool operator== (const OptionalRef<T>& p1, const OptionalRef<T>& p2) | ||
{ | ||
if (p1.has_value() != p2.has_value()) | ||
return false; | ||
|
||
if (! p1.has_value()) | ||
return true; // both nullopt | ||
|
||
return *p1 == *p2; | ||
} | ||
|
||
template <typename T> | ||
bool operator!= (const OptionalRef<T>& p1, const OptionalRef<T>& p2) | ||
{ | ||
return ! (p1 == p2); | ||
} | ||
|
||
template <typename T> | ||
bool operator== (const OptionalRef<T>& p1, std::nullopt_t) | ||
{ | ||
return ! p1.has_value(); | ||
} | ||
|
||
template <typename T> | ||
bool operator!= (const OptionalRef<T>& p1, std::nullopt_t) | ||
{ | ||
return p1.has_value(); | ||
} | ||
|
||
template <typename T> | ||
bool operator== (std::nullopt_t, const OptionalRef<T>& p1) | ||
{ | ||
return ! p1.has_value(); | ||
} | ||
|
||
template <typename T> | ||
bool operator!= (std::nullopt_t, const OptionalRef<T>& p1) | ||
{ | ||
return p1.has_value(); | ||
} | ||
|
||
template <typename T> | ||
bool operator== (const OptionalRef<T>& p1, const std::remove_cv_t<T>& p2) | ||
{ | ||
if (! p1.has_value()) | ||
return false; | ||
return *p1 == p2; | ||
} | ||
|
||
template <typename T> | ||
bool operator!= (const OptionalRef<T>& p1, const std::remove_cv_t<T>& p2) | ||
{ | ||
return ! (p1 == p2); | ||
} | ||
|
||
template <typename T> | ||
bool operator== (const std::remove_cv_t<T>& p2, const OptionalRef<T>& p1) | ||
{ | ||
return p1 == p2; | ||
} | ||
|
||
template <typename T> | ||
bool operator!= (const std::remove_cv_t<T>& p2, const OptionalRef<T>& p1) | ||
{ | ||
return p1 != p2; | ||
} | ||
} // namespace chowdsp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.