added base64 to core library
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 31 Oct 2022 19:39:23 +0000 (14:39 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 31 Oct 2022 19:39:23 +0000 (14:39 -0500)
core/container/array.onyx
core/encoding/base64.onyx [new file with mode: 0644]
core/std.onyx
core/time/date.onyx
tests/stdlib/base64 [new file with mode: 0644]
tests/stdlib/base64.onyx [new file with mode: 0644]

index 3d5f3169ac8784bedd859e5f44ae51adc6c7620d..3bbd3b00ae20c356cf016cd939b7425c35b35267 100644 (file)
@@ -305,6 +305,8 @@ contains :: #match #locked {
     }
 }
 
+empty :: (arr: [] $T) => arr.count == 0;
+
 // Uses '+' to sum.
 sum :: (arr: [] $T, start: T = 0) -> T {
     sum := start;
diff --git a/core/encoding/base64.onyx b/core/encoding/base64.onyx
new file mode 100644 (file)
index 0000000..d4c9454
--- /dev/null
@@ -0,0 +1,89 @@
+package core.encoding.base64
+
+encode :: (data: [] u8, allocator := context.allocator) -> [] u8 {
+    out := make([..] u8, allocator=allocator);
+
+    for i: range.{0, data.count - 2, 3} {
+        c1 := data[i + 0];
+        c2 := data[i + 1];
+        c3 := data[i + 2];
+
+        out << encode_map[c1 >> 2];
+        out << encode_map[((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4)];
+        out << encode_map[((c2 & 0xf) << 2) | ((c3 & 0xc0) >> 6)];
+        out << encode_map[c3 & 0x3f];
+    }
+
+    if data.count % 3 == 1 {
+        c := data[data.count - 1];
+        out << encode_map[c >> 2];
+        out << encode_map[(c & 0x3) << 4];
+        out << #char "=";
+        out << #char "=";
+
+    } elseif data.count % 3 == 2 {
+        c1 := data[data.count - 2];
+        c2 := data[data.count - 1];
+        out << encode_map[c1 >> 2];
+        out << encode_map[((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4)];
+        out << encode_map[(c2 & 0xf) << 2];
+        out << #char "=";
+    }
+
+    return out;
+}
+
+decode :: (data: [] u8, allocator := context.allocator) -> [] u8 {
+    if data.count % 4 != 0 do return null_str;
+
+    out := make([..] u8, allocator=allocator);
+
+    for i: range.{0, data.count, 4} {
+        c1 := data[i + 0];
+        c2 := data[i + 1];
+        c3 := data[i + 2];
+        c4 := data[i + 3];
+
+        v1 := decode_map[c1 - #char "+"];
+        v2 := decode_map[c2 - #char "+"];
+        v3 := decode_map[c3 - #char "+"];
+        v4 := decode_map[c4 - #char "+"];
+
+        o1 := (v1 << 2)         | ((v2 & 0x30) >> 4);
+        o2 := ((v2 & 0xf) << 4) | ((v3 & 0x3c) >> 2);
+        o3 := ((v3 & 0x3) << 6) | (v4 & 0x3f);
+
+        out << o1;
+        if c3 != #char "=" do out << o2;
+        if c4 != #char "=" do out << o3;
+    }
+
+    return out;
+}
+
+
+#local
+encode_map := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+// Use as:
+//     decode_map[ch - #char "+"];
+#local
+decode_map := u8.[
+    62, // +
+    0, 0, 0, // , - .   Invalid
+    63, // /
+    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // 0-9
+    0, 0, 0, 0, 0, 0, 0, // : ; < = > ? @   Invalid
+
+    // A-Z
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+    10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+    20, 21, 22, 23, 24, 25,
+
+    0, 0, 0, 0, 0, 0, // [ \ ] ^ _ `
+
+    26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+    36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+    46, 47, 48, 49, 50, 51,
+];
+
index c13c94f793dc220b7ed7dc19c003e1dc4f0a856a..76e445cabfda157775618f9a174f13fb4e0dbf15 100644 (file)
@@ -41,8 +41,6 @@ package core
 
 #load "./misc/any_utils"
 
-#load "./encoding/csv"
-
 #local runtime :: package runtime
 #if runtime.runtime == .Wasi || runtime.runtime == .Onyx {
     #load "./os/file"
@@ -75,6 +73,9 @@ package core
 #if runtime.runtime != .Custom {
     #load "./runtime/info/helper"
     #load "./stdio"
+
+    #load "./encoding/base64"
+    #load "./encoding/csv"
 }
 
 #if runtime.Multi_Threading_Enabled {
index 72c9cdfe7363058b29abdc552ef3850ea911f30d..0323e82744059aea2c20150555cb62911ca221ba 100644 (file)
@@ -14,6 +14,10 @@ Date :: struct {
 #inject Date {
     month_durations := u32.[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
 
+    make :: (year, month, day: i32) -> Date {
+        return .{ year, month - 1, day - 1 };
+    }
+
     add_months :: (d: Date, days: i32) -> Date {
         nd := d;
 
@@ -51,13 +55,13 @@ Date :: struct {
     }
 
     before :: (d1, d2: Date) -> bool {
-        if d1.year != d2.year do return d1.year < d2.year;
+        if d1.year  != d2.year  do return d1.year  < d2.year;
         if d1.month != d2.month do return d1.month < d2.month;
         return d1.day < d2.day;
     }
 
     after :: (d1, d2: Date) -> bool {
-        if d1.year != d2.year do return d1.year > d2.year;
+        if d1.year  != d2.year  do return d1.year  > d2.year;
         if d1.month != d2.month do return d1.month > d2.month;
         return d1.day > d2.day;
     }
diff --git a/tests/stdlib/base64 b/tests/stdlib/base64
new file mode 100644 (file)
index 0000000..f5577a3
--- /dev/null
@@ -0,0 +1,11 @@
+Many hands make light work.
+light w
+light wo
+light wor
+
+
+TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu
+bGlnaHQgdw==
+bGlnaHQgd28=
+bGlnaHQgd29y
+bGlnaHQgd29yaw==
diff --git a/tests/stdlib/base64.onyx b/tests/stdlib/base64.onyx
new file mode 100644 (file)
index 0000000..db7645c
--- /dev/null
@@ -0,0 +1,32 @@
+use core.encoding
+
+decode_test :: () {
+    for .[
+        "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu",
+        "bGlnaHQgdw==",
+        "bGlnaHQgd28=",
+        "bGlnaHQgd29y",
+    ] {
+        core.println(base64.decode(it));
+    }
+}
+
+encode_test :: () {
+    for .[
+        "Many hands make light work.",
+        "light w",
+        "light wo",
+        "light wor",
+        "light work",
+    ] {
+        encoded := base64.encode(it);
+        core.println(encoded);
+    }
+}
+
+main :: () {
+    decode_test();
+    core.println("\n");
+    encode_test();
+}
+