commit 06227a27310424de3f349a3610d929b73805a9cb
Author: Michael Sippel <micha@fragmental.art>
Date:   Tue Jan 28 22:33:08 2025 +0100

    posint morphisms in C

diff --git a/morphisms/Makefile b/morphisms/Makefile
new file mode 100644
index 0000000..4eb2d4d
--- /dev/null
+++ b/morphisms/Makefile
@@ -0,0 +1,11 @@
+TARGETS=lib/posint.so
+
+all: $(TARGETS)
+
+lib/%.so: src/%.c
+	gcc -shared -o $@ -fPIC $<
+
+clean:
+	rm $(TARGETS)
+
+.PHONY: all clean
diff --git a/morphisms/posint.morphism-base b/morphisms/posint.morphism-base
new file mode 100644
index 0000000..417618c
--- /dev/null
+++ b/morphisms/posint.morphism-base
@@ -0,0 +1,36 @@
+morph_digit_as_char_to_uint8 (Radix:ℤ_16)
+    <Digit Radix> ~ Char ~ Ascii ~ Byte
+--> <Digit Radix> ~ x86.UInt8 ~ Byte
+@lib/posint.so:src/posint.c
+
+morph_digit_as_uint8_to_char (Radix:ℤ_16)
+      <Digit Radix> ~ x86.UInt8 ~ Byte
+-->   <Digit Radix> ~ Char ~ Ascii ~ Byte
+@lib/posint.so:src/posint.c
+
+morph_posint_radix (SrcRadix:ℤ, DstRadix:ℤ)
+      ℕ
+    ~ <PosInt SrcRadix LittleEndian>
+    ~ [~<LengthPrefix x86.UInt64> <Digit SrcRadix>~x86.UInt64]
+-->   ℕ
+    ~ <PosInt DstRadix LittleEndian>
+    ~ [~<LengthPrefix x86.UInt64> <Digit DstRadix>~x86.UInt64]
+@lib/posint.so:src/posint.c
+
+morph_posint_endianness (Radix:ℤ)
+      ℕ
+    ~ <PosInt Radix LittleEndian>
+    ~ [~<LengthPrefix x86.UInt64> <Digit Radix> ~ x86.UInt64]
+-->   ℕ
+    ~ <PosInt Radix BigEndian>
+    ~ [~<LengthPrefix x86.UInt64> <Digit Radix> ~ x86.UInt64]
+@lib/posint.so:src/posint.c
+
+morph_posint_endianness (Radix:ℤ)
+      ℕ
+    ~ <PosInt Radix BigEndian>
+    ~ [~<LengthPrefix x86.UInt64> <Digit Radix> ~ x86.UInt64]
+-->   ℕ
+    ~ <PosInt Radix LittleEndian>
+    ~ [~<LengthPrefix x86.UInt64> <Digit Radix> ~ x86.UInt64]
+@lib/posint.so:src/posint.c
diff --git a/morphisms/src/length_prefix_array.c b/morphisms/src/length_prefix_array.c
new file mode 100644
index 0000000..4f908e6
--- /dev/null
+++ b/morphisms/src/length_prefix_array.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <stdint.h>
+
+struct LengthPrefixUInt64Array {
+    uint64_t len;
+    uint64_t items[];
+};
+
+void length_prefix_uint64_array_clear(
+    struct LengthPrefixUInt64Array * data
+) {
+    data->len = 0;
+}
+
+void length_prefix_uint64_array_push(
+    struct LengthPrefixUInt64Array * data,
+    uint64_t value
+) {
+    data->items[ data->len ] = value;
+    data->len += 1;
+}
+
+int length_prefix_uint64_array_reverse(
+    struct LengthPrefixUInt64Array const * restrict src,
+    struct LengthPrefixUInt64Array * restrict dst
+) {
+    dst->len = src->len;
+    for(uint64_t i = 0; i < src->len; ++i) {
+        dst->items[i] = src->items[src->len - i - 1];
+    }
+    return 0;
+}
+
+void length_prefix_uint64_array_dump(
+    struct LengthPrefixUInt64Array const * data
+) {
+    printf("Len = %d, [", data->len);
+    for( uint64_t i = 0; i < data->len; ++i ) {
+        printf("%d; ", data->items[i]);
+    }
+    printf("]\n");
+}
diff --git a/morphisms/src/posint.c b/morphisms/src/posint.c
new file mode 100644
index 0000000..5d25f20
--- /dev/null
+++ b/morphisms/src/posint.c
@@ -0,0 +1,85 @@
+#include <stdint.h>
+#include "length_prefix_array.c"
+
+int morph_digit_as_char_to_uint8(
+    char const * restrict src,
+    uint8_t * restrict dst
+) {
+    if( *src >= '0' && *src <= '9' )
+        *dst = *src - '0';
+    else if( *src >= 'a' && *src <= 'f')
+        *dst = 0xa + *src - 'a';
+    else if( *src >= 'A' && *src <= 'F')
+        *dst = 0xa + *src - 'A';
+    else
+        return -1;
+
+    return 0;
+}
+
+int morph_digit_as_char_to_uint64(
+    char const * restrict src,
+    uint64_t * restrict dst
+) {
+    if( *src >= '0' && *src <= '9' )
+        *dst = *src - '0';
+    else if( *src >= 'a' && *src <= 'f')
+        *dst = 0xa + *src - 'a';
+    else if( *src >= 'A' && *src <= 'F')
+        *dst = 0xa + *src - 'A';
+    else
+        return -1;
+
+    return 0;
+}
+
+int morph_digit_as_uint8_to_char(
+    uint8_t const * restrict src,
+    char * restrict dst
+) {
+    if ( *src < 10 )
+        *dst = *src + '0';
+    else if( *dst < 16 )
+        *dst = *src - 0xa + 'a';
+    else
+        return -1;
+
+    return 0;
+}
+
+/* switches endianness by reversing the digit sequence
+ */
+int morph_posint_endianness(
+    uint64_t const radix,
+
+    struct LengthPrefixUInt64Array const * restrict src,
+    struct LengthPrefixUInt64Array * restrict dst
+) {
+    return length_prefix_uint64_array_reverse( src, dst );
+}
+
+/* morph radix in little endian
+ */
+int morph_posint_radix(
+    uint64_t const src_radix,
+    uint64_t const dst_radix,
+
+    struct LengthPrefixUInt64Array const * restrict src,
+    struct LengthPrefixUInt64Array * restrict dst
+) {
+    uint64_t value = 0;
+
+    for( uint64_t i = 0; i < src->len; ++i ) {
+        value *= src_radix;
+        value += src->items[src->len - i - 1];
+    }
+
+    length_prefix_uint64_array_clear( dst );
+
+    while( value > 0 ) {
+        length_prefix_uint64_array_push( dst, value % dst_radix );
+        value /= dst_radix;
+    }
+
+    return 0;
+}