changelog shortlog graph tags branches files raw help

Mercurial > core / changeset: leb128 tests

changeset 547: ac01164b4141
parent 546: 8200daaf8199
child 548: b57066450cfa
author: Richard Westhaver <ellis@rwest.io>
date: Mon, 15 Jul 2024 15:18:03 -0400
files: lisp/std/num/leb128.lisp lisp/std/pkg.lisp lisp/std/tests.lisp
description: leb128 tests
     1.1--- a/lisp/std/num/leb128.lisp	Sun Jul 14 22:34:13 2024 -0400
     1.2+++ b/lisp/std/num/leb128.lisp	Mon Jul 15 15:18:03 2024 -0400
     1.3@@ -1,6 +1,8 @@
     1.4 ;;; leb128.lisp --- Little-Endian Base 128 Variable Encoding
     1.5 
     1.6-;; (U)LEB128 encoders
     1.7+;; (U)LEB128 encoders based on CL-LEB128
     1.8+
     1.9+;; see https://github.com/mahirvaluj/cl-leb128/blob/main/leb128.lisp
    1.10 
    1.11 ;;; Commentary:
    1.12 
    1.13@@ -11,8 +13,64 @@
    1.14 ;;; Code:
    1.15 (in-package :std/num)
    1.16 
    1.17-(defun encode-unsigned-leb128 (int)
    1.18-  "Encode an integer INT as an octet-vector with LEB128 encoding."
    1.19+(defun encode-leb128 (i)
    1.20+  "Encode an integer of arbitrary length into a leb128 unsigned-8 buffer"
    1.21+  (let ((more t) (curr) (in 0) (int (make-array
    1.22+                                     4
    1.23+                                     :adjustable t
    1.24+                                     :fill-pointer 0
    1.25+                                     :element-type '(unsigned-byte 8)))) ;(neg (< i 0))
    1.26+    (declare (fixnum i in))
    1.27+    (loop while more do
    1.28+      (setf curr (logand i #x7f))
    1.29+      (setf i (ash i -7))
    1.30+      (if (or (and (= i 0)  (= (logand curr #x40) 0))
    1.31+              (and (= i -1) (= (logand curr #x40) 64)))
    1.32+          (setf more nil)
    1.33+          (setf curr (logior curr #x80)))
    1.34+      (vector-push-extend curr int)
    1.35+      (incf in))
    1.36+    (let ((ret (make-array (length int) :element-type '(unsigned-byte 8) :initial-contents int)))
    1.37+      ret)))
    1.38+
    1.39+(defun read-leb128 (s &optional (start 0))
    1.40+  "decode signed integer from stream. Returns (values decoded-integer
    1.41+num-bytes-consumed)"
    1.42+  (declare (fixnum start))
    1.43+  (when (not (= start 0))
    1.44+    (loop for i from 0 upto start do (read-byte s)))
    1.45+  (let ((result 0) (shift 0) (curr) (counter 0))
    1.46+    (declare (fixnum result shift counter))
    1.47+    (loop do 
    1.48+         (setf curr (read-byte s))
    1.49+         (setf result (logior result (the fixnum (ash (logand curr #x7f) shift))))
    1.50+         (setf shift (+ 7 shift))
    1.51+         (incf counter)
    1.52+         (when (= 0 (logand curr #x80))
    1.53+           (if (= 64 (logand curr #x40))
    1.54+               (return-from read-leb128 (values (logior result (the fixnum (ash (lognot 0) shift))) counter))
    1.55+               (return-from read-leb128 (values result counter)))))))
    1.56+
    1.57+(defun decode-leb128 (buf &optional (start 0))
    1.58+  "decode signed integer from buffer. Returns (values decoded-integer
    1.59+num-bytes-consumed)"
    1.60+  (declare (fixnum start) (vector buf))
    1.61+  (let ((result 0) (shift 0) (curr 0) (counter 0))
    1.62+    (declare (fixnum result shift counter))
    1.63+    (loop do 
    1.64+         (setf curr (the (unsigned-byte 8) (aref buf start)))
    1.65+         (setf start (+ 1 start))
    1.66+         (setf result (logior result (the fixnum (ash (logand curr #x7f) shift))))
    1.67+         (setf shift (+ 7 shift))
    1.68+         (incf counter)
    1.69+         (when (= 0 (logand curr #x80))
    1.70+           (if (= 64 (logand curr #x40))
    1.71+               (return-from decode-leb128 (values (logior result (the fixnum (ash (lognot 0) shift))) counter))
    1.72+               (return-from decode-leb128 (values result counter)))))))
    1.73+
    1.74+(declaim (ftype (function (fixnum) (simple-array (unsigned-byte 8))) encode-uleb128))
    1.75+(defun encode-uleb128 (int)
    1.76+  "Encode an integer INT as a ULEB128 byte array."
    1.77   (declare (fixnum int))
    1.78   (let ((more t) (curr) (in 0) (ret (make-array
    1.79                                      (if (zerop int)
    1.80@@ -27,19 +85,36 @@
    1.81              (setf curr (logior curr #x80)))
    1.82          (setf (aref ret in) curr)
    1.83          (incf in))
    1.84-    ret))
    1.85+    (coerce ret 'simple-array)))
    1.86 
    1.87-(declaim (ftype (function ((simple-array unsigned-byte) &optional t) fixnum) decode-unsigned-leb128))
    1.88-(defun decode-unsigned-leb128 (bits &optional (start 0))
    1.89-  "Decode an unsigned integer from LEB128-encoded octet-vector BITS."
    1.90-  (declare (type (array unsigned-byte) bits))
    1.91+(declaim (ftype (function ((array (unsigned-byte 8)) &optional t) fixnum) decode-uleb128))
    1.92+(defun decode-uleb128 (bits &optional (start 0))
    1.93+  "Decode an unsigned integer from ULEB128 byte array."
    1.94   (let ((result 0) (shift 0) (curr) (counter 0))
    1.95-    (declare (fixnum result shift counter))
    1.96+    (declare (fixnum result shift counter start)
    1.97+             ((array (unsigned-byte 8)) bits))
    1.98     (loop do 
    1.99-         (setf curr (the (unsigned-byte 8) (aref bits start)))
   1.100+         (setf curr (aref bits start))
   1.101          (setf start (+ 1 start))
   1.102          (setf result (logior result (the fixnum (ash (logand curr #x7f) shift))))
   1.103          (setf shift (+ 7 shift))
   1.104          (incf counter)
   1.105          (when (= 0 (logand curr #x80))
   1.106-           (return-from decode-unsigned-leb128 (values result counter))))))
   1.107+           (return-from decode-uleb128 (values result counter))))))
   1.108+
   1.109+(defun read-uleb128 (s &optional (start 0))
   1.110+  "Decode an arbitrarily large unsigned integer from stream. Skip
   1.111+START number bytes. Return (values integer-decoded
   1.112+num-bytes-consumed)"
   1.113+  (declare (fixnum start))
   1.114+  (when (not (= start 0))
   1.115+    (loop for i from 0 upto start do (read-byte s)))
   1.116+  (let ((result 0) (shift 0) (curr) (counter 0))
   1.117+    (declare (fixnum result shift counter))
   1.118+    (loop do 
   1.119+         (setf curr (read-byte s))
   1.120+         (setf result (logior result (the fixnum (ash (logand curr #x7f) shift))))
   1.121+         (setf shift (+ 7 shift))
   1.122+         (incf counter)
   1.123+         (when (= 0 (logand curr #x80))
   1.124+           (return-from read-uleb128 (values result counter))))))
     2.1--- a/lisp/std/pkg.lisp	Sun Jul 14 22:34:13 2024 -0400
     2.2+++ b/lisp/std/pkg.lisp	Mon Jul 15 15:18:03 2024 -0400
     2.3@@ -106,7 +106,14 @@
     2.4    :encode-float32
     2.5    :decode-float32
     2.6    :encode-float64
     2.7-   :decode-float64))
     2.8+   :decode-float64
     2.9+   ;; num/leb128
    2.10+   :read-leb128
    2.11+   :encode-leb128
    2.12+   :decode-leb128
    2.13+   :read-uleb128
    2.14+   :encode-uleb128
    2.15+   :decode-uleb128))
    2.16 
    2.17 (defpkg :std/stream
    2.18   (:use :cl :sb-gray)
     3.1--- a/lisp/std/tests.lisp	Sun Jul 14 22:34:13 2024 -0400
     3.2+++ b/lisp/std/tests.lisp	Mon Jul 15 15:18:03 2024 -0400
     3.3@@ -251,16 +251,26 @@
     3.4                x) ;; 2
     3.5          '(42 42 2)))))
     3.6 
     3.7-(deftest bits (:skip t)
     3.8-  (define-bitfield testbits
     3.9-    (a boolean)
    3.10-    (b (signed-byte 2))
    3.11-    (c (unsigned-byte 3) :initform 1)
    3.12-    (d (integer -100 100))
    3.13-    (e (member foo bar baz)))
    3.14+(define-bitfield testbits
    3.15+  (a boolean)
    3.16+  (b (signed-byte 2))
    3.17+  (c (unsigned-byte 3) :initform 1)
    3.18+  (d (integer -100 100))
    3.19+  (e (member foo bar baz)))
    3.20+
    3.21+(deftest bits ()
    3.22   (let ((bits (make-testbits)))
    3.23     (is (not (testbits-a bits)))
    3.24     (is (= 0 (testbits-b bits)))
    3.25     (is (= 1 (testbits-c bits)))
    3.26     (is (= -100 (testbits-d bits)))
    3.27     (is (eql 'foo (testbits-e bits)))))
    3.28+
    3.29+(deftest leb128 ()
    3.30+  (loop for i from 0 below 1000
    3.31+        do (is (= i (decode-uleb128 (encode-uleb128 i)))))
    3.32+  (signals division-by-zero (decode-uleb128 (encode-uleb128 -1)))
    3.33+  (loop for i from -1000 below 0
    3.34+        do (is (= i (decode-leb128 (encode-leb128 i))))
    3.35+        do (is (= (* i i) (decode-leb128 (encode-leb128 (* i i)))))))
    3.36+