From c3c103e1a9ae4e1ad0725c775da64b29a1e2e9ba Mon Sep 17 00:00:00 2001
From: Ichthyostega
Date: Fri, 11 Sep 2026 23:22:03 +0200
Subject: [PATCH] Parameters: mark out the base operations of a Scale
Scales are defined as descriptor records and will be used as const.
Besides some information functions, a Scale
* allows to conform a value to be compliant with the Scale's constraints
* can ''join'' and thus apply a ''feed'' on top of a ''base value'';
this is the foundation for applying an automation function, while
handling multiplicative and logarithmic cases properly
---
src/lib/allocation-cluster.hpp | 4 +-
src/lib/par/scale.hpp | 88 +++++++++++++++++++++++++-
tests/lib/par/parameter-scale-test.cpp | 15 +++--
wiki/thinkPad.ichthyo.mm | 81 +++++++++++++++++-------
4 files changed, 157 insertions(+), 31 deletions(-)
diff --git a/src/lib/allocation-cluster.hpp b/src/lib/allocation-cluster.hpp
index 6734a224b..4e591039a 100644
--- a/src/lib/allocation-cluster.hpp
+++ b/src/lib/allocation-cluster.hpp
@@ -27,9 +27,9 @@
** mostly at start and then hold and use the memory, the allocation is never
** actually _closed_ — implying that further allocations can be added during
** the whole life time, which may possibly even trigger a further base allocation
- ** if storage space in the last Extent is exhausted. In theory, it would be possible
+ ** if storage space if the last Extent is exhausted. In theory, it would be possible
** to use a custom allocation (in the AllocationCluster::StorageManager::Extents,
- ** which is a lib::LinkedElements and could be parametrised with a allocator template).
+ ** which is a lib::LinkedElements and could be parametrised with an allocator template).
** Allocations are never discarded, and thus any alloted memory will be kept until
** the whole AllocationCluster is destroyed as a compound.
** \par using as STL allocator
diff --git a/src/lib/par/scale.hpp b/src/lib/par/scale.hpp
index bb219c76e..aaa12fe60 100644
--- a/src/lib/par/scale.hpp
+++ b/src/lib/par/scale.hpp
@@ -63,12 +63,98 @@ namespace par {
optional minUse{};
optional maxUse{};
optional neutral{};
- optional defaultVal{};
+ optional defVal{};
/////////////////////////////OOO »Sentinels« and nominal scales?
bool zyclic{false};
+
+ /* ===== information functions ===== */
+
+ bool isValid() const;
+
+ /* ===== conforming operations ===== */
+
+ VAL conform (VAL const&) const;
+
+ template
+ VAL join (VAL const&, SRC const&, Scale const&) const;
+ VAL join (VAL const&, VAL const&) const;
};
+ /* ===== information functions ===== */
+
+ /** self consistency check */
+ template
+ inline bool
+ Scale::isValid() const
+ {
+ return ((not minVal or not maxVal)
+ or *minVal <= *maxVal
+ )
+ and (not minUse
+ or (not minVal or *minVal <= *minUse)
+ )
+ and (not maxUse
+ or (not maxVal or *maxUse <= *maxVal)
+ )
+ and ((not minUse or not maxUse)
+ or *minUse <= *maxUse
+ )
+ and (not neutral
+ or ( (not maxVal or *neutral <= *maxVal)
+ and (not minVal or *minVal <= *neutral)
+ )
+ )
+ and (not defVal
+ or ( (not maxVal or *defVal <= *maxVal)
+ and (not minVal or *minVal <= *defVal)
+ )
+ )
+ and (not zyclic
+ or (minVal and maxVal)
+ or (minVal and neutral)
+ or (neutral and maxVal)
+ )
+ ;
+ }
+
+
+ /* ===== conforming operations ===== */
+
+ /**
+ * Accommodate a raw value from the underlying domain,
+ * so that it conforms with this Scale definition.
+ */
+ template
+ inline VAL
+ Scale::conform (VAL const& rawVal) const
+ {
+ UNIMPLEMENTED ("Scale conforming");
+ }
+
+ /**
+ * Join and combine an additional feed value with an anchor value.
+ * @note actual joining operation is picked based on both scales and types involved.
+ * @remark notably multiplicative contributions and logarithmic scales to be considered.
+ */
+ template
+ template
+ inline VAL
+ Scale::join (VAL const& value, SRC const& feed, Scale const& feedScale) const
+ {
+ UNIMPLEMENTED ("join a feed with a base value, observing Scale constraints");
+ }
+
+ /**
+ * Simplified join() variant, assuming the feed is based on the same scale.
+ */
+ template
+ inline VAL
+ Scale::join (VAL const& vaule, VAL const& feed) const
+ {
+ UNIMPLEMENTED ("join a feed with a base value within same Scale");
+ }
+
}} // namespace lib::par
#endif /*LIB_PAR_SCALE_H*/
diff --git a/tests/lib/par/parameter-scale-test.cpp b/tests/lib/par/parameter-scale-test.cpp
index 9de75e9bd..e6dc296e0 100644
--- a/tests/lib/par/parameter-scale-test.cpp
+++ b/tests/lib/par/parameter-scale-test.cpp
@@ -18,7 +18,7 @@
#include "test/run.hpp"
//#include "test/test-helper.hpp"
-#include "lib/par/parameter.hpp"
+#include "lib/par/scale.hpp"
#include "test/diagnostic-output.hpp"/////////////TODO
//#include
@@ -58,14 +58,21 @@ namespace test{
run (Arg)
{
simpleUsage();
- verify_typeMarker();
+ verify_Bounds();
}
void
simpleUsage()
{
- UNIMPLEMENTED ("nebbich");
+ Scale scale = {.minVal = -5, .maxVal = 23};
+ CHECK (scale.isValid());
+
+ CHECK (-5 == scale.conform (-55));
+ CHECK (23 == scale.conform (+55));
+
+ CHECK ( 5 == scale.join (2,3) );
+ CHECK (-5 == scale.join (23,-55));
}
@@ -73,7 +80,7 @@ namespace test{
* @todo WIP 9/26 🔁 define ⟶ implement
*/
void
- verify_typeMarker()
+ verify_Bounds()
{
}
};
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 5e3529027..64d7146f1 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -85424,7 +85424,8 @@
-
+
+
@@ -85551,9 +85552,10 @@
-
+
+
-
+
@@ -85564,8 +85566,15 @@
+
+
+
+
+
+
-
+
+
@@ -85593,7 +85602,8 @@
-
+
+
@@ -85867,7 +85877,8 @@
-
+
+
@@ -85916,11 +85927,19 @@
-
+
+
+
+
+
+ während dem Neuhinzufügen könnten Render-Worker concurrent den Index verwenden — hierfür gibt es aber keinerlei Konsistenz-Garantie (nur die Payload Storage-Adressen in der Deque sind garantiert stabil) ⟹ »undefined behaviour«
+
+
+
-
+
@@ -85933,27 +85952,24 @@
address computation touches nothing a writer mutates.
-
-
-
-
-class ScaleRegistry
+
+class ScaleRegistry
{
static constexpr size_t CHUNK = 256;
- static constexpr size_t MAX = 256; // ≙ 65536 scales
+ static constexpr size_t MAX = 256; // ≙ 65536 scales
struct Chunk { ScaleDescriptor slot[CHUNK]; };
- std::array, MAX> chunk_{};
- std::mutex writeGuard_; // writers only
- size_t next_ {0}; // guarded
+ std::array<std atomic="#DEFAULT" size="2"><chunk size="2">, MAX> chunk_{};
+ std::mutex writeGuard_; // writers only
+ size_t next_ {0}; // guarded
public:
- ScaleDescriptor const&
+ ScaleDescriptor const&
operator[] (ScaleID id) const // lock-free, engine path
{
return chunk_[id / CHUNK].load (std::memory_order_acquire)
- ->slot[id % CHUNK];
+ ->slot[id % CHUNK];
}
ScaleID
@@ -85961,16 +85977,13 @@
{
std::lock_guard lock{writeGuard_};
size_t id = next_++;
- auto& head = chunk_[id / CHUNK];
+ auto& head = chunk_[id / CHUNK];
if (not head.load (std::memory_order_relaxed))
head.store (new Chunk{}, std::memory_order_release);
- head.load (std::memory_order_relaxed)->slot[id % CHUNK] = std::move(def);
+ head.load (std::memory_order_relaxed)->slot[id % CHUNK] = std::move(def);
return ScaleID{id};
}
};
-
-
-
@@ -85998,6 +86011,7 @@
+
@@ -86024,6 +86038,10 @@
+
+
+
+
@@ -86231,6 +86249,21 @@
+
+
+
+
+
+
+
+ ...nicht aber die Registrierung und Einbindung in die Parameter
+
+
+
+
+
+
+