summaryrefslogtreecommitdiff
path: root/zap/src/mem
diff options
context:
space:
mode:
Diffstat (limited to 'zap/src/mem')
-rw-r--r--zap/src/mem/fndbyte.S59
-rw-r--r--zap/src/mem/fndchr.S57
-rw-r--r--zap/src/mem/foreach.S71
-rw-r--r--zap/src/mem/memcat.c16
-rw-r--r--zap/src/mem/memcmp.c21
-rw-r--r--zap/src/mem/memcp.S107
-rw-r--r--zap/src/mem/memeq.S82
-rw-r--r--zap/src/mem/memfill.S45
-rw-r--r--zap/src/mem/memgen.c25
-rw-r--r--zap/src/mem/strcat.c19
-rw-r--r--zap/src/mem/strcmp.c23
-rw-r--r--zap/src/mem/strcp.S53
-rw-r--r--zap/src/mem/streq.S57
-rw-r--r--zap/src/mem/strfill.S48
-rw-r--r--zap/src/mem/strlen.S46
-rw-r--r--zap/src/mem/utf8dec.c51
-rw-r--r--zap/src/mem/utf8declen.c35
-rw-r--r--zap/src/mem/utf8enc.S152
-rw-r--r--zap/src/mem/utf8enclen.S80
-rw-r--r--zap/src/mem/win1252dec.c111
-rw-r--r--zap/src/mem/win1252enc.c113
21 files changed, 1271 insertions, 0 deletions
diff --git a/zap/src/mem/fndbyte.S b/zap/src/mem/fndbyte.S
new file mode 100644
index 0000000..4413b42
--- /dev/null
+++ b/zap/src/mem/fndbyte.S
@@ -0,0 +1,59 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_fndbyte
+
+zap_fndbyte:
+
+ /*
+ void const * ptr
+ zap_sz num
+ unsigned char byte
+ */
+
+#if defined(__amd64__)
+
+ # rax: Address of the current element.
+ # rdi: Address of the first element.
+ # rsi: Address of the element after the last element.
+ # rdx: Byte value.
+ # rcx: Current byte.
+
+ movq %rdi,%rax
+
+ addq %rdi,%rsi
+
+ # Iterate over the array:
+.loop:
+
+ # Check if we have reached the end of the array:
+ cmpq %rax,%rsi
+ je .nfnd
+
+ # Check if we have found the byte value:
+ movb (%rax),%cl
+ cmpb %cl,%dl
+ je .fnd
+
+ # Continue to the next byte:
+ incq %rax
+ jmp .loop
+
+ # Found:
+.fnd:
+
+ subq %rdi,%rax
+ ret
+
+ # Not found:
+.nfnd:
+
+ movq $0xFFFFFFFFFFFFFFFF,%rax
+ ret
+
+#endif
diff --git a/zap/src/mem/fndchr.S b/zap/src/mem/fndchr.S
new file mode 100644
index 0000000..2982e7e
--- /dev/null
+++ b/zap/src/mem/fndchr.S
@@ -0,0 +1,57 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Pudhic License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_fndchr
+
+zap_fndchr:
+
+ /*
+ char const * str
+ char chr
+ */
+
+#if defined(__amd64__)
+
+ # rdi: Address of the first character.
+ # rsi: Character to be found.
+ # rax: Address of the current character.
+ # rdx: Current character.
+
+ movq %rdi,%rax
+
+ # Iterate over the string:
+.loop:
+
+ # Copy the character into a register:
+ movb (%rax),%dl
+
+ # Check if we have found the character:
+ cmpb %dl,%sil
+ je .fnd
+
+ # Check if we have found the null-terminator:
+ testb %dl,%dl
+ jz .nfnd
+
+ # Continue to the next character:
+ incq %rax
+ jmp .loop
+
+ # Found:
+.fnd:
+
+ subq %rdi,%rax
+ ret
+
+ # Not found:
+.nfnd:
+
+ movq $0xFFFFFFFFFFFFFFFF,%rax
+ ret
+
+#endif
diff --git a/zap/src/mem/foreach.S b/zap/src/mem/foreach.S
new file mode 100644
index 0000000..fe96538
--- /dev/null
+++ b/zap/src/mem/foreach.S
@@ -0,0 +1,71 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_foreach
+
+zap_foreach:
+
+ /*
+ void * ptr
+ zap_sz sz
+ zap_sz num
+ void (* fn)(void *)
+ */
+
+#if defined(__amd64__)
+
+ # rbx: Address of the current element.
+ # r12: Address of the element after the last input element.
+ # r13: Size of each input element.
+ # r14: Address of the function.
+
+ # We're gonna use callee-saved registers for storing values so they don't get overwritten with each function call.
+
+ # Push the callee-saved registers:
+ pushq %rbx
+ pushq %r12
+ pushq %r13
+ pushq %r14
+
+ # Move registers into place:
+ movq %rdi,%rbx
+ movq %rsi,%r13
+ movq %rcx,%r14
+
+ # Get the one-past-the-end address:
+ movq %rdx,%r12
+ imulq %r13,%r12 # Calculate the array size in bytes (sz * num). We're using signed multiply because the equivalent using the unsigned instruction would use more instructions.
+ addq %rbx,%r12
+
+ # Iterate through the array:
+.loop:
+
+ # Check if we have reached the one-past-the-end address:
+ cmpq %rbx,%r12
+ je .done
+
+ # Call the provided function:
+ movq %rbx,%rdi # Provide the current address to the function.
+ call *%r14 # We don't need to save any registers for this as we only use callee-saved registers.
+
+ # Continue to the next element:
+ addq %r13,%rbx
+ jmp .loop
+
+ # Finish:
+.done:
+
+ # Restore the callee-saved registers:
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %rbx
+
+ ret
+
+#endif
diff --git a/zap/src/mem/memcat.c b/zap/src/mem/memcat.c
new file mode 100644
index 0000000..f3e9a9b
--- /dev/null
+++ b/zap/src/mem/memcat.c
@@ -0,0 +1,16 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+#include <zap/mem.h>
+
+#include <stddef.h>
+
+void zap_memcat(void const * const _lptr,zap_sz const _llen,void const * const _rptr,zap_sz const _rlen,void * const _buf) {
+ zap_memcp(_lptr,_llen,_buf);
+ zap_memcp(_rptr,_rlen,(unsigned char *)_buf + _llen);
+}
diff --git a/zap/src/mem/memcmp.c b/zap/src/mem/memcmp.c
new file mode 100644
index 0000000..601da99
--- /dev/null
+++ b/zap/src/mem/memcmp.c
@@ -0,0 +1,21 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+#include <zap/mem.h>
+
+zap_cmp zap_memcmp(void const * const _lstr,zap_sz const _num,void const * const _rstr) {
+ unsigned char const * lpos = _lstr;
+ unsigned char const * rpos = _rstr;
+ unsigned char const * const afterlbuf = lpos + _num;
+ for (;lpos != afterlbuf;++lpos,++rpos) {
+ unsigned char const lbyte = *lpos;
+ unsigned char const rbyte = *rpos;
+ sus_likely (lbyte != rbyte) {return lbyte < rbyte ? zap_lt : zap_gt;}
+ }
+ return zap_eq;
+}
diff --git a/zap/src/mem/memcp.S b/zap/src/mem/memcp.S
new file mode 100644
index 0000000..ead0718
--- /dev/null
+++ b/zap/src/mem/memcp.S
@@ -0,0 +1,107 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_memcp
+
+zap_memcp:
+
+ /*
+ void const * in
+ zap_sz num
+ void * out
+ */
+#if defined(__amd64__)
+
+ # rdi: Address of the current input element.
+ # rsi: Number of remaining elements.
+ # rdx: Address of the current output element.
+ # rcx: Current element.
+ # xmm0: Current element.
+ # ymm0: Current element.
+
+#if defined(__AVX__)
+ # AVX support 256-bit moves.
+
+ # Copy 32 bytes:
+.big20cp:
+
+ # Check if there are at least 32 bytes remaining:
+ cmpq $0x20,%rsi
+ jl .big10cp # If not, skip to the 10 byte copying.
+
+ # Copy:
+ vmovups (%rdi),%ymm0 # Move into a register.
+ vmovups %ymm0,(%rdx) # And then back into memory.
+
+ # Continue:
+ addq $0x20,%rdi
+ addq $0x20,%rdx
+ subq $0x20,%rsi
+ jmp .big20cp
+
+#endif
+
+ # AMD64 requires SSE(2).
+
+ # Copy 16 bytes:
+.big10cp:
+
+ # Check if there are at least 16 bytes remaining:
+ cmpq $0x10,%rsi
+ jl .wrdcp
+
+ # Copy:
+ movdqu (%rdi),%xmm0
+ movdqu %xmm0,(%rdx)
+
+ # Continue:
+ addq $0x10,%rdi
+ addq $0x10,%rdx
+ subq $0x10,%rsi
+ jmp .big10cp
+
+ # Copy one word (8 bytes):
+.wrdcp:
+
+ # Check if there are at least 8 bytes remaining:
+ cmpq $0x8,%rsi
+ jl .bytecp
+
+ # Copy:
+ movq (%rdi),%rcx
+ movq %rcx,(%rdx)
+
+ # Continue:
+ addq $0x8,%rdi
+ addq $0x8,%rdx
+ subq $0x8,%rsi
+ jmp .wrdcp
+
+ # Copy one byte:
+.bytecp:
+
+ # Check if we have any bytes remaining:
+ testq %rsi,%rsi
+ jz .done
+
+ # Copy:
+ movb (%rdi),%cl
+ movb %cl,(%rdx)
+
+ # Continue:
+ incq %rdi
+ incq %rdx
+ decq %rsi
+ jmp .bytecp
+
+ # Finish:
+.done:
+
+ ret
+
+#endif
diff --git a/zap/src/mem/memeq.S b/zap/src/mem/memeq.S
new file mode 100644
index 0000000..cf554c2
--- /dev/null
+++ b/zap/src/mem/memeq.S
@@ -0,0 +1,82 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_memeq
+
+zap_memeq:
+
+ /*
+ void const * lptr
+ zap_sz num
+ void const * rptr
+ */
+
+#if defined(__amd64__)
+
+ /* rdi: Left pointer. */
+ /* rsi: Number of remaining elements. */
+ /* rdx: Right pointer. */
+ /* rax: Current left element. */
+ /* rcx: Current right element. */
+
+ /* Compare words: */
+.wrdcmp:
+
+ /* Check if there's at least one word left: */
+ cmpq $0x8,%rsi
+ jl .bytecmp /* If not, skip to byte checks: */
+
+ /* Copy the values into registers: */
+ movq (%rdi),%rax
+ movq (%rdx),%rcx
+
+ /* Check if the words are equal: */
+ cmpq %rax,%rcx
+ jne .neq
+
+ /* Mark eight more bytes as equal: */
+ addq $0x8,%rdi
+ addq $0x8,%rdx
+ subq $0x8,%rsi
+
+ /* Continue to the next word: */
+ jmp .wrdcmp
+
+ /* Compare bytes: */
+.bytecmp:
+
+ /* Check if there are any bytes left: */
+ testq %rsi,%rsi
+ jz .eq /* If we have reached the final element, all previous elements have compared equal, and the memory sequences are equal. */
+
+ /* Copy the values into registers: */
+ movb (%rdi),%al
+ movb (%rdx),%cl
+
+ cmpb %al,%cl
+ jne .neq
+
+ /* Mark another byte as equal: */
+ incq %rdi
+ incq %rdx
+ decq %rsi
+
+ /* Continue to the next byte: */
+ jmp .bytecmp
+
+ /* The memory sequences have compared equal: */
+.eq:
+ movb $0xFF,%al
+ ret
+
+ /* The memory sequences have compared NOT equal: */
+.neq:
+ movb $0x0,%al
+ ret
+
+#endif
diff --git a/zap/src/mem/memfill.S b/zap/src/mem/memfill.S
new file mode 100644
index 0000000..63a1aad
--- /dev/null
+++ b/zap/src/mem/memfill.S
@@ -0,0 +1,45 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_memfill
+
+zap_memfill:
+
+ /*
+ void const * ptr
+ zap_sz num
+ unsigned char val
+ */
+
+#if defined(__amd64__)
+
+ # rdi: Address of the current element.
+ # rsi: Address of the element after the last element.
+ # rdx: Byte value.
+
+ addq %rdi,%rsi
+
+ # Iterate over buffer:
+.loop:
+
+ # Check if we have reached the final element:
+ cmpq %rdi,%rsi
+ je .done # Exit loop if we have.
+
+ # Set the value of the current element:
+ movb %dl,(%rdi)
+
+ # Continue to next element:
+ incq %rdi
+ jmp .loop
+
+ # Finish:
+.done:
+ ret
+
+#endif
diff --git a/zap/src/mem/memgen.c b/zap/src/mem/memgen.c
new file mode 100644
index 0000000..a39e326
--- /dev/null
+++ b/zap/src/mem/memgen.c
@@ -0,0 +1,25 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+/*.globl zap_memgen
+
+zap_memgen:*/
+
+ /*
+ void * ptr
+ zap_sz sz
+ zap_sz num
+ void (* fn)(zap_sz,void *)
+ */
+
+void zap_memgen(void * const _ptr,zap_sz const _sz,zap_sz const _num,void (* const _fn)(zap_sz,void *)) {
+ unsigned char * ptr = _ptr;
+ unsigned char * const afterbuf = ptr + _sz * _num;
+ for (;ptr != afterbuf;ptr += _sz) {_fn((ptr - (unsigned char *)_ptr) / _sz,ptr);}
+}
+
diff --git a/zap/src/mem/strcat.c b/zap/src/mem/strcat.c
new file mode 100644
index 0000000..f7f66c8
--- /dev/null
+++ b/zap/src/mem/strcat.c
@@ -0,0 +1,19 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+#include <zap/mem.h>
+
+#include <stddef.h>
+
+void zap_strcat(char const * const _lstr,char const * const _rstr,char * const _buf) {
+ zap_sz const llen = zap_strlen (_lstr);
+ zap_sz const rlen = zap_strlen (_rstr);
+ zap_memcp(_lstr,llen,_buf);
+ zap_memcp(_rstr,rlen,_buf + llen);
+ _buf[llen + rlen] = '\x0';
+}
diff --git a/zap/src/mem/strcmp.c b/zap/src/mem/strcmp.c
new file mode 100644
index 0000000..691717a
--- /dev/null
+++ b/zap/src/mem/strcmp.c
@@ -0,0 +1,23 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+#include <zap/mem.h>
+
+#include <stdint.h>
+
+zap_cmp zap_strcmp(char const * const _lstr,char const * const _rstr) {
+ unsigned char const * lpos = (unsigned char const *)_lstr;
+ unsigned char const * rpos = (unsigned char const *)_rstr;
+ for (;;++lpos,++rpos) {
+ unsigned char const lchr = *lpos;
+ unsigned char const rchr = *rpos;
+ sus_likely (lchr != rchr) {return lchr < rchr ? zap_lt : zap_gt;}
+ sus_unlikely (lchr == (unsigned char)0x0) {return zap_eq;}
+ }
+ sus_unreach();
+}
diff --git a/zap/src/mem/strcp.S b/zap/src/mem/strcp.S
new file mode 100644
index 0000000..04c3198
--- /dev/null
+++ b/zap/src/mem/strcp.S
@@ -0,0 +1,53 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_strcp
+
+zap_strcp:
+
+ /*
+ char const * in
+ char const * out
+ */
+
+#if defined(__amd64__)
+
+ # rax: Address of the current input character.
+ # rdi: Address of the first input character.
+ # rsi: Address of the current output character.
+ # rdx: Current character.
+
+ movq %rdi,%rax
+
+ # Iterate over the strings:
+.loop:
+
+ # Copy character:
+ movb (%rax),%dl # Move it into a register...
+ movb %dl,(%rsi) # ... and then back into memory.
+
+ # Check if we have reached the null-terminator:
+ testb %dl,%dl
+ jz .done
+
+ # Continue to the next character:
+
+ incq %rax
+ incq %rsi
+ jmp .loop
+
+ # Finish:
+.done:
+
+ # Get the length of the (input) string:
+ subq %rdi,%rax
+ decq %rax # We do not count the null-terminator in the string length.
+
+ ret
+
+#endif
diff --git a/zap/src/mem/streq.S b/zap/src/mem/streq.S
new file mode 100644
index 0000000..d331e93
--- /dev/null
+++ b/zap/src/mem/streq.S
@@ -0,0 +1,57 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_streq
+
+zap_streq:
+
+ /*
+ char const * lstr
+ char const * rstr
+ */
+
+#if defined(__amd64__)
+
+ # rdi: Address of the current left character.
+ # rsi: Address of the current right character.
+ # rax: Current left character.
+ # rdx: Current right character.
+
+ # Iterate over the strings:
+.loop:
+
+ # Copy the characters into registers:
+ movb (%rdi),%al
+ movb (%rsi),%dl
+
+ # Check if the characters are equal:
+ cmpb %al,%dl
+ jne .neq # If not, the strings also aren't equal.
+
+ # Check if we have reached the null-terminator:
+ testb %al,%al
+ jz .eq # If so, all previous characters have compared equal, and the strings are equal.
+
+ # Continue to the next characters:
+ incq %rdi
+ incq %rsi
+ jmp .loop
+
+ # The strings have compared equal:
+.eq:
+
+ movb $0xFF,%al
+ ret
+
+ /* The strings have compared unequal: */
+.neq:
+
+ movb $0x0,%al
+ ret
+
+#endif
diff --git a/zap/src/mem/strfill.S b/zap/src/mem/strfill.S
new file mode 100644
index 0000000..277865e
--- /dev/null
+++ b/zap/src/mem/strfill.S
@@ -0,0 +1,48 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_strfill
+
+zap_strfill:
+
+ /*
+ char * str
+ char chr
+ */
+
+#if defined(__amd64__)
+
+ # rdi: Address of the first character of the string.
+ # rsi: Fill character.
+ # rax: Address of the current character.
+
+ movq %rdi,%rax
+
+ # Iterate over string:
+.loop:
+
+ # Check if we have reached the null-terminator:
+ cmpb $0x0,(%rax)
+ je .done # Exit loop if we have.
+
+ # Set the value of the current element:
+ movb %sil,(%rax)
+
+ # Continue to next character:
+ incq %rax
+ jmp .loop
+
+ # Finish:
+.done:
+
+ # Get the length of the string:
+ subq %rdi,%rax
+
+ ret
+
+#endif
diff --git a/zap/src/mem/strlen.S b/zap/src/mem/strlen.S
new file mode 100644
index 0000000..4cb435f
--- /dev/null
+++ b/zap/src/mem/strlen.S
@@ -0,0 +1,46 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_strlen
+
+zap_strlen:
+
+ /*
+ char const * str
+ */
+
+#if defined(__amd64__)
+
+ # rax: Address of the current character.
+ # rdx: Current character.
+
+ movq %rdi,%rax
+
+ # Iterate over the string:
+.loop:
+
+ # Move the character into a register:
+ movb (%rax),%dl
+
+ # Check if we have reached the null-terminator:
+ testb %dl,%dl
+ jz .done # If so, we are done.
+
+ # Continue to the next character:
+ incq %rax
+ jmp .loop
+
+ # Done:
+.done:
+
+ # Get the length:
+ subq %rdi,%rax
+
+ ret
+
+#endif
diff --git a/zap/src/mem/utf8dec.c b/zap/src/mem/utf8dec.c
new file mode 100644
index 0000000..32ebd00
--- /dev/null
+++ b/zap/src/mem/utf8dec.c
@@ -0,0 +1,51 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+#include <zap/mem.h>
+
+void zap_utf8dec(zap_chr8 const * const _in,zap_chr20 * const _out) {
+ zap_chr8 const * in = _in;
+ zap_chr20 * out = _out;
+ for (;;++out) {
+ zap_chr8 const oct = *in;
+ if (oct >= 0xF0u) { /* Four octets. */
+ zap_chr20 chr = ((zap_chr20)oct ^ 0xF0u) << 0x12u;
+ ++in;
+ chr += ((zap_chr20)*in ^ 0x80u) << 0xCu;
+ ++in;
+ chr += ((zap_chr20)*in ^ 0x80u) << 0x6u;
+ ++in;
+ chr += (zap_chr20)*in ^ 0x80u;
+ ++in;
+ *out = chr;
+ continue;
+ }
+ if (oct >= 0xE0u) { /* Three octets. */
+ zap_chr20 chr = ((zap_chr20)oct ^ 0xE0u) << 0xCu;
+ ++in;
+ chr += ((zap_chr20)*in ^ 0x80u) << 0x6u;
+ ++in;
+ chr += (zap_chr20)*in ^ 0x80u;
+ ++in;
+ *out = chr;
+ continue;
+ }
+ if (oct >= 0xC0u) { /* Two octets. */
+ zap_chr20 chr = ((zap_chr20)oct ^ 0xC0u) << 0x6u;
+ ++in;
+ chr += (zap_chr20)*in ^ 0x80u;
+ ++in;
+ *out = chr;
+ continue;
+ }
+ /* One octet. */
+ *out = oct;
+ ++in;
+ sus_unlikely (oct == 0x0u) {break;}
+ }
+}
diff --git a/zap/src/mem/utf8declen.c b/zap/src/mem/utf8declen.c
new file mode 100644
index 0000000..202e995
--- /dev/null
+++ b/zap/src/mem/utf8declen.c
@@ -0,0 +1,35 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+#include <zap/mem.h>
+
+#include <stddef.h>
+
+zap_sz zap_utf8declen(zap_chr8 const * const _in) {
+ zap_sz len = 0x0u;
+ zap_chr8 const * in;
+ for (in = _in;;++len) {
+ zap_chr8 const oct = *in;
+ sus_unlikely (oct == 0x0u) {break;}
+ if (oct >= 0xF0u) {
+ in += 0x4u;
+ continue;
+ }
+ if (oct >= 0xE0u) {
+ in += 0x3u;
+ continue;
+ }
+ if (oct >= 0xC0u) {
+ in += 0x2u;
+ continue;
+ }
+ ++in;
+ continue;
+ }
+ return len;
+}
diff --git a/zap/src/mem/utf8enc.S b/zap/src/mem/utf8enc.S
new file mode 100644
index 0000000..24e09d8
--- /dev/null
+++ b/zap/src/mem/utf8enc.S
@@ -0,0 +1,152 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_utf8enc
+
+zap_utf8enc:
+
+ /*
+ zap_chr20 const * in
+ zap_chr8 * out
+ */
+
+#if defined(__amd64__)
+
+ # rdi: Current input codepoint.
+ # rsi: Current output octet.
+ # rax: Current codepoint.
+ # rdx: Temporary.
+
+ # Iterate over the input:
+.loop:
+
+ movl (%rdi),%eax
+
+ cmpl $0xFFFF,%eax
+ jg .oct4
+
+ cmpl $0x7FF,%eax
+ jg .oct3
+
+ cmpl $0x7F,%eax
+ jg .oct2 # Otherwise, only one octet is needed.
+
+ # One octet:
+.oct1:
+
+ # Octet #0:
+ movb %al,(%rsi) # No conversion needed:
+
+ incq %rsi
+
+ # Test if we have reached the null-terminator:
+ testb %al,%al
+ jz .done
+
+ jmp .cnt
+
+ # Two octets:
+.oct2:
+
+ /* Octet #0: */
+ movl %eax,%edx
+ shrl $0x6,%edx
+ orb $0xC0,%dl
+ movb %dl,(%rsi)
+
+ incq %rsi
+
+ # Octet #1:
+ movl %eax,%edx
+ andb $0x3F,%dl
+ orb $0x80,%dl
+ movb %dl,(%rsi)
+
+ incq %rsi
+
+ jmp .cnt
+
+ # Three octets:
+.oct3:
+
+ # Octet #0:
+ movl %eax,%edx
+ shrl $0xC,%edx
+ orb $0xE0,%dl
+ movb %dl,(%rsi)
+
+ incq %rsi
+
+ # Octet #1:
+ movl %eax,%edx
+ shrl $0x6,%edx
+ andb $0x3F,%dl
+ orb $0x80,%dl
+ movb %dl,(%rsi)
+
+ incq %rsi
+
+ # Octet #2:
+ movl %eax,%edx
+ andb $0x3F,%dl
+ orb $0x80,%dl
+ movb %dl,(%rsi)
+
+ incq %rsi
+
+ jmp .cnt
+
+ # Four octets:/
+.oct4:
+
+ # Octet #0:
+ movl %eax,%edx
+ shrl $0x12,%edx
+ orb $0xF0,%dl
+ movb %dl,(%rsi)
+
+ incq %rsi
+
+ # Octet #1:
+ movl %eax,%edx
+ shrl $0xC,%edx
+ andb $0x3F,%dl
+ orb $0x80,%dl
+ movb %dl,(%rsi)
+
+ incq %rsi
+
+ # Octet #2:
+ movl %eax,%edx
+ shrl $0x6,%edx
+ andb $0x3F,%dl
+ orb $0x80,%dl
+ movb %dl,(%rsi)
+
+ incq %rsi
+
+ # Octet #3:
+ movl %eax,%edx
+ andb $0x3F,%dl
+ orb $0x80,%dl
+ movb %dl,(%rsi)
+
+ incq %rsi
+
+ # Continue to the next codepoint:
+.cnt:
+
+ addq $0x4,%rdi
+ jmp .loop
+
+ # Done:
+.done:
+
+ ret
+
+#endif
diff --git a/zap/src/mem/utf8enclen.S b/zap/src/mem/utf8enclen.S
new file mode 100644
index 0000000..1c80e6a
--- /dev/null
+++ b/zap/src/mem/utf8enclen.S
@@ -0,0 +1,80 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_utf8enclen
+
+zap_utf8enclen:
+
+ /*
+ zap_chr20 const * utf20
+ */
+
+#if defined(__amd64__)
+
+ # rdi: Address of the current character.
+ # rax: Length of the string.
+ # rsi: Current character.
+
+ movq $0x0,%rax
+
+ # Iterate over the input:
+.loop:
+
+ movl (%rdi),%esi
+
+ # Test if we have reached the null-terminator:
+ testl %esi,%esi
+ jz .done
+
+ cmpl $0xFFFF,%esi
+ jg .oct4
+
+ cmpl $0x7FF,%esi
+ jg .oct3
+
+ cmpl $0x7F,%esi
+ jg .oct2
+
+ # One octet:
+.oct1:
+
+ incq %rax
+
+ jmp .cnt
+
+ # Two octets:
+.oct2:
+
+ addq $0x2,%rax
+
+ jmp .cnt
+
+ # Three octets:
+.oct3:
+
+ addq $0x3,%rax
+
+ jmp .cnt
+
+ # Four octets:
+.oct4:
+
+ addq $0x4,%rax
+
+ # Continue to the next codepoint:
+.cnt:
+
+ addq $0x4,%rdi
+ jmp .loop
+
+ # Done:
+.done:
+
+ ret
+
+#endif
diff --git a/zap/src/mem/win1252dec.c b/zap/src/mem/win1252dec.c
new file mode 100644
index 0000000..529bbe3
--- /dev/null
+++ b/zap/src/mem/win1252dec.c
@@ -0,0 +1,111 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+#include <zap/mem.h>
+
+void zap_win1252dec(zap_chr8 const * const _in,zap_chr20 * const _out) {
+ zap_chr8 const * in = _in;
+ zap_chr20 * out = _out;
+ for (;;++in,++out) {
+ zap_chr8 const chr = *in;
+ switch (chr) {
+ default:
+ *out = *in;
+ break;
+ case 0x81: /* Bad characters. */
+ case 0x8D:
+ case 0x8F:
+ case 0x90:
+ case 0x9D:
+ *out = 0xFFFDu; /* REPLACEMENT CHARACTER */
+ break;
+ case 0x80:
+ *out = 0x20ACu;
+ break;
+ case 0x82:
+ *out = 0x201Au;
+ break;
+ case 0x83:
+ *out = 0x192u;
+ break;
+ case 0x84:
+ *out = 0x201Eu;
+ break;
+ case 0x85:
+ *out = 0x2026u;
+ break;
+ case 0x86:
+ *out = 0x2020u;
+ break;
+ case 0x87:
+ *out = 0x2021u;
+ break;
+ case 0x88:
+ *out = 0x2C6u;
+ break;
+ case 0x89:
+ *out = 0x2030u;
+ break;
+ case 0x8A:
+ *out = 0x160u;
+ break;
+ case 0x8B:
+ *out = 0x2039u;
+ break;
+ case 0x8C:
+ *out = 0x152u;
+ break;
+ case 0x8E:
+ *out = 0x17Du;
+ break;
+ case 0x91:
+ *out = 0x2018u;
+ break;
+ case 0x92:
+ *out = 0x2019u;
+ break;
+ case 0x93:
+ *out = 0x201Cu;
+ break;
+ case 0x94:
+ *out = 0x201Du;
+ break;
+ case 0x95:
+ *out = 0x2022u;
+ break;
+ case 0x96:
+ *out = 0x2013u;
+ break;
+ case 0x97:
+ *out = 0x2014u;
+ break;
+ case 0x98:
+ *out = 0x2DCu;
+ break;
+ case 0x99:
+ *out = 0x2122u;
+ break;
+ case 0x9A:
+ *out = 0x161u;
+ break;
+ case 0x9B:
+ *out = 0x203Au;
+ break;
+ case 0x9C:
+ *out = 0x153u;
+ break;
+ case 0x9E:
+ *out = 0x17Eu;
+ break;
+ case 0x9F:
+ *out = 0x178u;
+ break;
+ }
+ sus_unlikely (chr == 0x0u) {break;}
+ }
+}
diff --git a/zap/src/mem/win1252enc.c b/zap/src/mem/win1252enc.c
new file mode 100644
index 0000000..147ddaf
--- /dev/null
+++ b/zap/src/mem/win1252enc.c
@@ -0,0 +1,113 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+#include <zap/mem.h>
+
+void zap_win1252enc(zap_chr20 const * const _in,zap_chr8 * const _out) {
+ zap_chr20 const * in = _in;
+ zap_chr8 * out = _out;
+ for (;;++in,++out) {
+ zap_chr20 const chr = *in;
+ zap_chr8 const bad = 0x3Fu;
+ switch (chr) {
+ default:
+ sus_unlikely (chr > 0xFFu) {
+ *out = bad;
+ break;
+ }
+ sus_unlikely (chr >= 0x80u && chr <= 0x9Fu) {
+ *out = bad;
+ break;
+ }
+ *out = *in;
+ break;
+ case 0x20ACu:
+ *out = 0x80u;
+ break;
+ case 0x201Au:
+ *out = 0x82u;
+ break;
+ case 0x192u:
+ *out = 0x83u;
+ break;
+ case 0x201Eu:
+ *out = 0x84u;
+ break;
+ case 0x2026u:
+ *out = 0x85u;
+ break;
+ case 0x2020u:
+ *out = 0x86u;
+ break;
+ case 0x2021u:
+ *out = 0x87u;
+ break;
+ case 0x2C6u:
+ *out = 0x88u;
+ break;
+ case 0x2030u:
+ *out = 0x89u;
+ break;
+ case 0x160u:
+ *out = 0x8Au;
+ break;
+ case 0x2039u:
+ *out = 0x8Bu;
+ break;
+ case 0x152u:
+ *out = 0x8Cu;
+ break;
+ case 0x17Du:
+ *out = 0x8Eu;
+ break;
+ case 0x2018u:
+ *out = 0x91u;
+ break;
+ case 0x2019u:
+ *out = 0x92u;
+ break;
+ case 0x201Cu:
+ *out = 0x93u;
+ break;
+ case 0x201Du:
+ *out = 0x94u;
+ break;
+ case 0x2022u:
+ *out = 0x95u;
+ break;
+ case 0x2013u:
+ *out = 0x96u;
+ break;
+ case 0x2014u:
+ *out = 0x97u;
+ break;
+ case 0x2DCu:
+ *out = 0x98u;
+ break;
+ case 0x2122u:
+ *out = 0x99u;
+ break;
+ case 0x161u:
+ *out = 0x9Au;
+ break;
+ case 0x203Au:
+ *out = 0x9Bu;
+ break;
+ case 0x153u:
+ *out = 0x9Cu;
+ break;
+ case 0x17Eu:
+ *out = 0x9Eu;
+ break;
+ case 0x178u:
+ *out = 0x9Fu;
+ break;
+ }
+ sus_unlikely (chr == 0x0u) {break;}
+ }
+}