diff mbox series

[1/8] util: add util_linear_map

Message ID 20241119142430.323074-1-prestwoj@gmail.com (mailing list archive)
State Accepted, archived
Headers show
Series [1/8] util: add util_linear_map | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
prestwoj/iwd-alpine-ci-fetch success Fetch PR
prestwoj/iwd-ci-fetch success Fetch PR
prestwoj/iwd-alpine-ci-setupell success Prep - Setup ELL
prestwoj/iwd-ci-gitlint success GitLint
prestwoj/iwd-ci-setupell success Prep - Setup ELL
prestwoj/iwd-ci-makedistcheck success Make Distcheck
prestwoj/iwd-alpine-ci-makedistcheck success Make Distcheck
prestwoj/iwd-ci-build success Build - Configure
prestwoj/iwd-alpine-ci-build success Build - Configure
prestwoj/iwd-ci-makecheckvalgrind success Make Check w/Valgrind
prestwoj/iwd-ci-clang success clang PASS
prestwoj/iwd-ci-makecheck success Make Check
prestwoj/iwd-alpine-ci-makecheckvalgrind success Make Check w/Valgrind
prestwoj/iwd-alpine-ci-makecheck success Make Check
prestwoj/iwd-ci-incremental_build success Incremental Build with patches
prestwoj/iwd-alpine-ci-incremental_build success Incremental Build with patches
prestwoj/iwd-ci-testrunner success test-runner PASS

Commit Message

James Prestwood Nov. 19, 2024, 2:24 p.m. UTC
This has been needed elsewhere but generally shortcuts could be
taken mapping with ranges starting/ending with zero. This is a
more general linear mapping utility to map values between any
two ranges.
---
 src/util.c | 30 ++++++++++++++++++++++++++++++
 src/util.h | 11 +++++++++++
 2 files changed, 41 insertions(+)
diff mbox series

Patch

diff --git a/src/util.c b/src/util.c
index a4a78fb6..a6ab9d85 100644
--- a/src/util.c
+++ b/src/util.c
@@ -312,6 +312,36 @@  bool util_ip_prefix_tohl(const char *ip, uint8_t *prefix_out,
 	return true;
 }
 
+/*
+ * Linearly maps @value (expected to be within range @a_start and @a_end) to
+ * a new value between @b_start and @b_end.
+ *
+ * Returns: false if
+ *   @value is not between @a_start and @a_end
+ *   @a_start/@a_end or @b_start/@b_end are equal.
+ */
+bool util_linear_map(double value, double a_start, double a_end,
+			double b_start, double b_end, double *mapped_value)
+{
+	/* Check value is within a's range */
+	if (a_start < a_end) {
+		if (value < a_start || value > a_end)
+			return false;
+	} else if (a_start > a_end) {
+		if (value > a_start || value < a_end)
+			return false;
+	} else
+		return false;
+
+	if (b_start == b_end)
+		return false;
+
+	*mapped_value = b_start + (((b_end - b_start) / (a_end - a_start)) *
+					(value - a_start));
+
+	return true;
+}
+
 struct scan_freq_set {
 	uint16_t channels_2ghz;
 	struct l_uintset *channels_5ghz;
diff --git a/src/util.h b/src/util.h
index dafa446d..9f3f0a57 100644
--- a/src/util.h
+++ b/src/util.h
@@ -106,6 +106,17 @@  static inline bool util_ip_subnet_match(uint8_t prefix_len,
 		  ~((1u << (8 - (prefix_len % 8))) - 1));
 }
 
+/*
+ * Linearly maps (interpolates) 'value' from range 'a' to range 'b'
+ *
+ * Fails if:
+ *    - value is not between a and b
+ *    - a_start == a_end
+ *    - b_start == b_end
+ */
+bool util_linear_map(double value, double a_start, double a_end,
+			double b_start, double b_end, double *mapped_value);
+
 typedef void (*scan_freq_set_func_t)(uint32_t freq, void *userdata);
 
 struct scan_freq_set *scan_freq_set_new(void);