summaryrefslogtreecommitdiff
path: root/AK
diff options
context:
space:
mode:
authorNicholas Baron <nicholas.baron.ten@gmail.com>2021-05-16 02:36:52 -0700
committerGitHub <noreply@github.com>2021-05-16 10:36:52 +0100
commitaa4d41fe2c473c3bb78327a1dbe8ec85530259ca (patch)
tree925d408b37ab1f7750a3af37adfb2949fcafa836 /AK
parentbbaa4630323c20e37e2a0ead478987cb5f02fc53 (diff)
downloadserenity-aa4d41fe2c473c3bb78327a1dbe8ec85530259ca.zip
AK+Kernel+LibELF: Remove the need for `IteratorDecision::Continue`
By constraining two implementations, the compiler will select the best fitting one. All this will require is duplicating the implementation and simplifying for the `void` case. This constraining also informs both the caller and compiler by passing the callback parameter types as part of the constraint (e.g.: `IterationFunction<int>`). Some `for_each` functions in LibELF only take functions which return `void`. This is a minimal correctness check, as it removes one way for a function to incompletely do something. There seems to be a possible idiom where inside a lambda, a `return;` is the same as `continue;` in a for-loop.
Diffstat (limited to 'AK')
-rw-r--r--AK/Concepts.h24
-rw-r--r--AK/InlineLinkedList.h10
2 files changed, 33 insertions, 1 deletions
diff --git a/AK/Concepts.h b/AK/Concepts.h
index 6f92b17be3..5394fe6ab8 100644
--- a/AK/Concepts.h
+++ b/AK/Concepts.h
@@ -6,6 +6,7 @@
#pragma once
+#include <AK/IterationDecision.h>
#include <AK/StdLibExtras.h>
namespace AK::Concepts {
@@ -27,6 +28,27 @@ concept Signed = IsSigned<T>;
template<typename T>
concept Unsigned = IsUnsigned<T>;
+template<typename T, typename U>
+concept SameAs = IsSame<T, U>;
+
+template<typename Func, typename... Args>
+concept VoidFunction = requires(Func func, Args... args)
+{
+ {
+ func(args...)
+ }
+ ->SameAs<void>;
+};
+
+template<typename Func, typename... Args>
+concept IteratorFunction = requires(Func func, Args... args)
+{
+ {
+ func(args...)
+ }
+ ->SameAs<IterationDecision>;
+};
+
#endif
}
@@ -36,7 +58,9 @@ concept Unsigned = IsUnsigned<T>;
using AK::Concepts::Arithmetic;
using AK::Concepts::FloatingPoint;
using AK::Concepts::Integral;
+using AK::Concepts::IteratorFunction;
using AK::Concepts::Signed;
using AK::Concepts::Unsigned;
+using AK::Concepts::VoidFunction;
#endif
diff --git a/AK/InlineLinkedList.h b/AK/InlineLinkedList.h
index e36e8830d4..06a0f38dfe 100644
--- a/AK/InlineLinkedList.h
+++ b/AK/InlineLinkedList.h
@@ -7,6 +7,7 @@
#pragma once
#include <AK/Assertions.h>
+#include <AK/Concepts.h>
#include <AK/Types.h>
namespace AK {
@@ -112,7 +113,7 @@ public:
return false;
}
- template<typename F>
+ template<IteratorFunction<T&> F>
IterationDecision for_each(F func) const
{
for (T* node = m_head; node; node = node->next()) {
@@ -123,6 +124,13 @@ public:
return IterationDecision::Continue;
}
+ template<VoidFunction<T&> F>
+ void for_each(F func) const
+ {
+ for (T* node = m_head; node; node = node->next())
+ func(*node);
+ }
+
using Iterator = InlineLinkedListIterator<T>;
friend Iterator;
Iterator begin() { return Iterator(m_head); }