diff --git a/.github/workflows/shared.yml b/.github/workflows/shared.yml index d9d503f82d..14af8e16d3 100644 --- a/.github/workflows/shared.yml +++ b/.github/workflows/shared.yml @@ -90,7 +90,6 @@ jobs: -Dpace=${{inputs.pace}} \ --summary all fi - - name: Run unit tests run: | zig build \ diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000000..00bb18361f --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,6 @@ +############################################################################### +# Bazel now uses Bzlmod by default to manage external dependencies. +# Please consider migrating your external dependencies from WORKSPACE to MODULE.bazel. +# +# For more details, please check https://github.com/bazelbuild/bazel/issues/18958 +############################################################################### diff --git a/bazel/third_party/softblas/BUILD.bazel b/bazel/third_party/softblas/BUILD.bazel new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bazel/third_party/softblas/softblas.BUILD b/bazel/third_party/softblas/softblas.BUILD new file mode 100644 index 0000000000..34c80c93e6 --- /dev/null +++ b/bazel/third_party/softblas/softblas.BUILD @@ -0,0 +1,117 @@ +# FILEPATH: /home/neal/lagoon/vere/bazel/third_party/softblas/softblas.BUILD + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +cc_library( + name = "softblas", + visibility = ["//visibility:public"], + deps = select({ + "@platforms//cpu:aarch64": [":softblas_aarch64"], + "@platforms//cpu:x86_64": [":softblas_x86_64"], + "//conditions:default": [], + }), +) + +cc_library( + name = "softblas_aarch64", + visibility = ["//visibility:public"], + hdrs = ["include/softblas.h"], + includes = ["include"], + srcs = [ + "include/softblas.h", + "src/softblas_state.c", + "src/blas/level1/sasum.c", + "src/blas/level1/dasum.c", + "src/blas/level1/hasum.c", + "src/blas/level1/qasum.c", + "src/blas/level1/saxpy.c", + "src/blas/level1/daxpy.c", + "src/blas/level1/haxpy.c", + "src/blas/level1/qaxpy.c", + "src/blas/level1/scopy.c", + "src/blas/level1/dcopy.c", + "src/blas/level1/hcopy.c", + "src/blas/level1/qcopy.c", + "src/blas/level1/sdot.c", + "src/blas/level1/ddot.c", + "src/blas/level1/hdot.c", + "src/blas/level1/qdot.c", + "src/blas/level1/snrm2.c", + "src/blas/level1/dnrm2.c", + "src/blas/level1/hnrm2.c", + "src/blas/level1/qnrm2.c", + "src/blas/level1/sscal.c", + "src/blas/level1/dscal.c", + "src/blas/level1/hscal.c", + "src/blas/level1/qscal.c", + "src/blas/level1/sswap.c", + "src/blas/level1/dswap.c", + "src/blas/level1/hswap.c", + "src/blas/level1/qswap.c", + "src/blas/level1/isamax.c", + "src/blas/level1/idamax.c", + "src/blas/level1/ihamax.c", + "src/blas/level1/iqamax.c", + "src/blas/level2/sgemv.c", + "src/blas/level2/dgemv.c", + "src/blas/level2/hgemv.c", + "src/blas/level2/qgemv.c", + "src/blas/level3/sgemm.c", + "src/blas/level3/dgemm.c", + "src/blas/level3/hgemm.c", + "src/blas/level3/qgemm.c" + ], + deps = ["@softfloat"], +) + +cc_library( + name = "softblas_x86_64", + visibility = ["//visibility:public"], + hdrs = ["include/softblas.h"], + includes = ["include"], + srcs = [ + "include/softblas.h", + "src/softblas_state.c", + "src/blas/level1/sasum.c", + "src/blas/level1/dasum.c", + "src/blas/level1/hasum.c", + "src/blas/level1/qasum.c", + "src/blas/level1/saxpy.c", + "src/blas/level1/daxpy.c", + "src/blas/level1/haxpy.c", + "src/blas/level1/qaxpy.c", + "src/blas/level1/scopy.c", + "src/blas/level1/dcopy.c", + "src/blas/level1/hcopy.c", + "src/blas/level1/qcopy.c", + "src/blas/level1/sdot.c", + "src/blas/level1/ddot.c", + "src/blas/level1/hdot.c", + "src/blas/level1/qdot.c", + "src/blas/level1/snrm2.c", + "src/blas/level1/dnrm2.c", + "src/blas/level1/hnrm2.c", + "src/blas/level1/qnrm2.c", + "src/blas/level1/sscal.c", + "src/blas/level1/dscal.c", + "src/blas/level1/hscal.c", + "src/blas/level1/qscal.c", + "src/blas/level1/sswap.c", + "src/blas/level1/dswap.c", + "src/blas/level1/hswap.c", + "src/blas/level1/qswap.c", + "src/blas/level1/isamax.c", + "src/blas/level1/idamax.c", + "src/blas/level1/ihamax.c", + "src/blas/level1/iqamax.c", + "src/blas/level2/sgemv.c", + "src/blas/level2/dgemv.c", + "src/blas/level2/hgemv.c", + "src/blas/level2/qgemv.c", + "src/blas/level3/sgemm.c", + "src/blas/level3/dgemm.c", + "src/blas/level3/hgemm.c", + "src/blas/level3/qgemm.c" + ], + deps = ["@softfloat"], +) diff --git a/build.zig b/build.zig index e6f1b25970..ded7b4cca2 100644 --- a/build.zig +++ b/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const VERSION = "3.1"; +const VERSION = "3.2"; const targets: []const std.Target.Query = &.{ .{ .cpu_arch = .aarch64, .os_tag = .macos, .abi = null }, @@ -283,6 +283,11 @@ fn build_single( .optimize = optimize, }); + const softblas = b.dependency("softblas", .{ + .target = target, + .optimize = optimize, + }); + const softfloat = b.dependency("softfloat", .{ .target = target, .optimize = optimize, @@ -485,10 +490,12 @@ fn build_single( pkg_noun.linkLibrary(pdjson.artifact("pdjson")); pkg_noun.linkLibrary(sigsegv.artifact("sigsegv")); pkg_noun.linkLibrary(softfloat.artifact("softfloat")); + pkg_noun.linkLibrary(softblas.artifact("softblas")); if (t.os.tag == .linux) pkg_noun.linkLibrary(unwind.artifact("unwind")); pkg_noun.linkLibrary(urcrypt.artifact("urcrypt")); pkg_noun.linkLibrary(whereami.artifact("whereami")); + pkg_noun.linkLibrary(zlib.artifact("z")); pkg_noun.linkLibC(); pkg_noun.addIncludePath(b.path("pkg/noun")); @@ -556,12 +563,16 @@ fn build_single( "jets/c/can.c", "jets/c/cap.c", "jets/c/cat.c", + "jets/c/clz.c", + "jets/c/ctz.c", "jets/c/cut.c", "jets/c/dis.c", "jets/c/dor.c", "jets/c/dvr.c", "jets/c/end.c", "jets/c/gor.c", + "jets/c/ham.c", + "jets/c/hew.c", "jets/c/lsh.c", "jets/c/mas.c", "jets/c/met.c", @@ -575,6 +586,7 @@ fn build_single( "jets/c/rap.c", "jets/c/rep.c", "jets/c/rev.c", + "jets/c/rig.c", "jets/c/rip.c", "jets/c/rsh.c", "jets/c/sqt.c", @@ -615,6 +627,8 @@ fn build_single( "jets/e/argon2.c", "jets/e/base.c", "jets/e/blake.c", + "jets/e/chacha.c", + "jets/e/crc32.c", "jets/e/cue.c", "jets/e/ed_add_double_scalarmult.c", "jets/e/ed_add_scalarmult_scalarmult_base.c", @@ -678,12 +692,16 @@ fn build_single( "jets/f/ut_mull.c", "jets/f/ut_nest.c", "jets/f/ut_rest.c", + "jets/g/plot.c", + "jets/i/lagoon.c", "jets/tree.c", + "jets/137/tree.c", "log.c", "manage.c", "nock.c", "options.c", "retrieve.c", + "ship.c", "serial.c", "trace.c", "urth.c", @@ -771,6 +789,7 @@ fn build_single( vere.linkLibrary(libuv.artifact("libuv")); vere.linkLibrary(lmdb.artifact("lmdb")); vere.linkLibrary(openssl.artifact("ssl")); + vere.linkLibrary(urcrypt.artifact("urcrypt")); vere.linkLibrary(zlib.artifact("z")); vere.linkLibrary(pkg_c3); vere.linkLibrary(pkg_ent); @@ -797,6 +816,10 @@ fn build_single( "io/hind.c", "io/http.c", "io/lick.c", + "io/lss.c", + "io/mesa.c", + "io/mesa/bitset.c", + "io/mesa/pact.c", "io/term.c", "io/unix.c", "ivory/ivory.c", @@ -873,6 +896,7 @@ fn build_single( urbit.linkLibrary(lmdb.artifact("lmdb")); urbit.linkLibrary(openssl.artifact("ssl")); urbit.linkLibrary(sigsegv.artifact("sigsegv")); + urbit.linkLibrary(urcrypt.artifact("urcrypt")); urbit.linkLibrary(whereami.artifact("whereami")); urbit.addCSourceFiles(.{ diff --git a/build.zig.zon b/build.zig.zon index f39c710e39..3f6a8c07b7 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -49,6 +49,9 @@ .softfloat = .{ .path = "./ext/softfloat", }, + .softblas = .{ + .path = "./ext/softblas", + }, .unwind = .{ .path = "./ext/unwind", }, diff --git a/ext/softblas/build.zig b/ext/softblas/build.zig new file mode 100644 index 0000000000..1fb3b066b5 --- /dev/null +++ b/ext/softblas/build.zig @@ -0,0 +1,80 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const lib = b.addStaticLibrary(.{ + .name = "softblas", + .target = target, + .optimize = optimize, + }); + + const dep_c = b.dependency("softblas", .{ + .target = target, + .optimize = optimize, + }); + + const softfloat = b.dependency("softfloat", .{ + .target = target, + .optimize = optimize, + }); + + lib.addIncludePath(dep_c.path("include")); + + lib.addCSourceFiles(.{ + .root = dep_c.path(""), + .files = &.{ + "src/softblas_state.c", + "src/blas/level1/sasum.c", + "src/blas/level1/dasum.c", + "src/blas/level1/hasum.c", + "src/blas/level1/qasum.c", + "src/blas/level1/saxpy.c", + "src/blas/level1/daxpy.c", + "src/blas/level1/haxpy.c", + "src/blas/level1/qaxpy.c", + "src/blas/level1/scopy.c", + "src/blas/level1/dcopy.c", + "src/blas/level1/hcopy.c", + "src/blas/level1/qcopy.c", + "src/blas/level1/sdot.c", + "src/blas/level1/ddot.c", + "src/blas/level1/hdot.c", + "src/blas/level1/qdot.c", + "src/blas/level1/snrm2.c", + "src/blas/level1/dnrm2.c", + "src/blas/level1/hnrm2.c", + "src/blas/level1/qnrm2.c", + "src/blas/level1/sscal.c", + "src/blas/level1/dscal.c", + "src/blas/level1/hscal.c", + "src/blas/level1/qscal.c", + "src/blas/level1/sswap.c", + "src/blas/level1/dswap.c", + "src/blas/level1/hswap.c", + "src/blas/level1/qswap.c", + "src/blas/level1/isamax.c", + "src/blas/level1/idamax.c", + "src/blas/level1/ihamax.c", + "src/blas/level1/iqamax.c", + "src/blas/level2/sgemv.c", + "src/blas/level2/dgemv.c", + "src/blas/level2/hgemv.c", + "src/blas/level2/qgemv.c", + "src/blas/level3/sgemm.c", + "src/blas/level3/dgemm.c", + "src/blas/level3/hgemm.c", + "src/blas/level3/qgemm.c", + }, + .flags = &.{ + "-fno-sanitize=all", + }, + }); + + lib.installHeader(dep_c.path("include/softblas.h"), "softblas.h"); + + lib.linkLibC(); + lib.linkLibrary(softfloat.artifact("softfloat")); + b.installArtifact(lib); +} diff --git a/ext/softblas/build.zig.zon b/ext/softblas/build.zig.zon new file mode 100644 index 0000000000..431171b53b --- /dev/null +++ b/ext/softblas/build.zig.zon @@ -0,0 +1,16 @@ +.{ + .name = "softblas", + .version = "0.0.1", + .dependencies = .{ + .softfloat = .{ + .path = "../softfloat", + }, + .softblas = .{ + .url = "https://github.com/urbit/SoftBLAS/archive/cbffb33f19ea02f9ffbd184d445123c57929ec53.tar.gz", + .hash = "1220617c11d869ef2316571a430f51f93470e2d714141deb3bdfaa6b578cf151f258", + }, + }, + .paths = .{ + "", + }, +} diff --git a/ext/urcrypt/build.zig b/ext/urcrypt/build.zig index 69af969ded..79a54ac576 100644 --- a/ext/urcrypt/build.zig +++ b/ext/urcrypt/build.zig @@ -28,6 +28,7 @@ pub fn build(b: *std.Build) void { lib.linkLibrary(libed25519(b, target, optimize)); lib.linkLibrary(libge_additions(b, target, optimize)); lib.linkLibrary(libkeccak_tiny(b, target, optimize)); + lib.linkLibrary(libmonocypher(b, target, optimize)); lib.linkLibrary(libscrypt(b, target, optimize)); lib.linkLibrary(libaes_siv(b, target, optimize)); @@ -44,6 +45,7 @@ pub fn build(b: *std.Build) void { "aes_siv.c", "argon.c", "blake3.c", + "chacha.c", "ed25519.c", "ge_additions.c", "keccak.c", @@ -418,6 +420,40 @@ fn libkeccak_tiny( return lib; } +fn libmonocypher( + b: *std.Build, + target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, +) *std.Build.Step.Compile { + const dep_c = b.dependency("urcrypt", .{ + .target = target, + .optimize = optimize, + }); + + const lib = b.addStaticLibrary(.{ + .name = "monocypher", + .target = target, + .optimize = optimize, + }); + + lib.linkLibC(); + + lib.addIncludePath(dep_c.path("monocypher")); + + lib.addCSourceFiles(.{ + .root = dep_c.path("monocypher"), + .files = &.{"monocypher.c"}, + .flags = &.{ + "-O2", + "-fno-sanitize=all", + }, + }); + + lib.installHeader(dep_c.path("monocypher/monocypher.h"), "monocypher.h"); + + return lib; +} + fn libscrypt( b: *std.Build, target: std.Build.ResolvedTarget, diff --git a/ext/urcrypt/build.zig.zon b/ext/urcrypt/build.zig.zon index 7732c2a5e2..b8da2ecc08 100644 --- a/ext/urcrypt/build.zig.zon +++ b/ext/urcrypt/build.zig.zon @@ -17,8 +17,8 @@ .hash = "1220bb683a6df744e618f58a008eaae3eb62b70a78334cec676bd82b1b9e8e944eeb", }, .urcrypt = .{ - .url = "https://github.com/urbit/urcrypt/archive/9ae5d604528bc54ae48430f55ebbb17b1ad7956c.tar.gz", - .hash = "1220b2847be5292d9f625b4e238794fcd0d9f944b2165deaf48e68d17d606e2f4205", + .url = "https://github.com/urbit/urcrypt/archive/e77a0998809f7552c455cf7bf8c1b68c141cce18.tar.gz", + .hash = "12202efcf40dcfed9a9b59bba4743cfd0c31364a6d7504724bd4d643b474ff69245b", }, }, .paths = .{ diff --git a/lldbinit.txt b/lldbinit.txt new file mode 100644 index 0000000000..d0f8a83b8e --- /dev/null +++ b/lldbinit.txt @@ -0,0 +1,4 @@ +pro hand -p true -s false -n false SIGBUS SIGSEGV +p (void)darwin_register_mach_exception_handler() +b u3m_bail +b malloc_error_break diff --git a/pkg/c3/defs.h b/pkg/c3/defs.h index a98e66bca6..dac060a816 100644 --- a/pkg/c3/defs.h +++ b/pkg/c3/defs.h @@ -5,6 +5,7 @@ #include "portable.h" #include "types.h" +#include #include @@ -51,7 +52,19 @@ /* Bit counting. */ -# define c3_bits_word(w) ((w) ? (32 - __builtin_clz(w)) : 0) +#if (32 == (CHAR_BIT * __SIZEOF_INT__)) +# define c3_lz_w __builtin_clz +# define c3_tz_w __builtin_ctz +# define c3_pc_w __builtin_popcount +#elif (32 == (CHAR_BIT * __SIZEOF_LONG__)) +# define c3_lz_w __builtin_clzl +# define c3_tz_w __builtin_ctzl +# define c3_pc_w __builtin_popcountl +#else +# error "port me" +#endif + +# define c3_bits_word(w) ((w) ? (32 - c3_lz_w(w)) : 0) /* Min and max. */ diff --git a/pkg/c3/motes.h b/pkg/c3/motes.h index 975554e94b..daf5b90896 100644 --- a/pkg/c3/motes.h +++ b/pkg/c3/motes.h @@ -68,6 +68,7 @@ # define c3__bcts c3_s4('b','c','t','s') # define c3__bczp c3_s4('b','c','z','p') # define c3__bead c3_s4('b','e','a','d') +# define c3__beam c3_s4('b','e','a','m') # define c3__bean c3_s4('b','e','a','n') # define c3__bear c3_s4('b','e','a','r') # define c3__bede c3_s4('b','e','d','e') @@ -258,6 +259,7 @@ # define c3__corp c3_s4('c','o','r','p') # define c3__corp c3_s4('c','o','r','p') # define c3__cow c3_s3('c','o','w') +# define c3__cplx c3_s3('c','p','l','x') # define c3__cpu c3_s3('c','p','u') # define c3__crad c3_s4('c','r','a','d') # define c3__cram c3_s4('c','r','a','m') @@ -430,6 +432,7 @@ # define c3__fit c3_s3('f','i','t') # define c3__fits c3_s4('f','i','t','s') # define c3__fix c3_s3('f','i','x') +# define c3__fixp c3_s3('f','i','x','p') # define c3__fl c3_s2('f','l') # define c3__flac c3_s4('f','l','a','c') # define c3__flag c3_s4('f','l','a','g') @@ -539,6 +542,7 @@ # define c3__head c3_s4('h','e','a','d') # define c3__heal c3_s4('h','e','a','l') # define c3__hear c3_s4('h','e','a','r') +# define c3__heer c3_s4('h','e','e','r') # define c3__hela c3_s4('h','e','l','a') # define c3__helm c3_s4('h','e','l','m') # define c3__helo c3_s4('h','e','l','o') @@ -555,6 +559,7 @@ # define c3__hind c3_s4('h','i','n','d') # define c3__hint c3_s4('h','i','n','t') # define c3__hit c3_s3('h','i','t') +# define c3__hmac c3_s4('h','m','a','c') # define c3__hmal c3_s4('h','m','a','l') # define c3__hold c3_s4('h','o','l','d') # define c3__hole c3_s4('h','o','l','e') @@ -602,6 +607,7 @@ # define c3__info c3_s4('i','n','f','o') # define c3__init c3_s4('i','n','i','t') # define c3__ins c3_s3('i','n','s') +# define c3__int2 c3_s4('i','n','t','2') # define c3__into c3_s4('i','n','t','o') # define c3__intr c3_s4('i','n','t','r') # define c3__inuk c3_s4('i','n','u','k') @@ -610,6 +616,7 @@ # define c3__is c3_s2('i','s') # define c3__item c3_s4('i','t','e','m') # define c3__ix c3_s2('i','x') +# define c3__i754 c3_s4('i','7','5','4') # define c3__j c3_s1('j') # define c3__jack c3_s4('j','a','c','k') # define c3__jam c3_s3('j','a','m') @@ -723,6 +730,8 @@ # define c3__lt c3_s2('l','t') # define c3__lull c3_s4('l','u','l','l') # define c3__lunt c3_s4('l','u','n','t') +# define c3__m c3_s1('m') +# define c3__mx c3_s2('m','x') # define c3__mach c3_s4('m','a','c','h') # define c3__mack c3_s4('m','a','c','k') # define c3__made c3_s4('m','a','d','e') @@ -749,7 +758,10 @@ # define c3__meme c3_s4('m','e','m','e') # define c3__memo c3_s4('m','e','m','o') # define c3__menu c3_s4('m','e','n','u') +# define c3__mesa c3_s4('m','e','s','a') # define c3__mesh c3_s4('m','e','s','h') +# define c3__mess c3_s4('m','e','s','s') +# define c3__mess_ser c3_s8('m','e','s','s','-', 's', 'e','r') # define c3__met c3_s3('m','e','t') # define c3__meta c3_s4('m','e','t','a') # define c3__mill c3_s4('m','i','l','l') @@ -851,6 +863,8 @@ # define c3__ovum c3_s4('o','v','u','m') # define c3__p c3_s1('p') # define c3__pack c3_s4('p','a','c','k') +# define c3__pact c3_s4('p','a','c','t') +# define c3__page c3_s4('p','a','g','e') # define c3__pair c3_s4('p','a','i','r') # define c3__palm c3_s4('p','a','l','m') # define c3__palq c3_s4('p','a','l','q') @@ -971,6 +985,7 @@ # define c3__rasp c3_s4('r','a','s','p') # define c3__raw c3_s3('r','a','w') # define c3__read c3_s4('r','e','a','d') +# define c3__real c3_s4('r','e','a','l') # define c3__reck c3_s4('r','e','c','k') # define c3__reef c3_s4('r','e','e','f') # define c3__resd c3_s4('r','e','s','d') @@ -1014,6 +1029,7 @@ # define c3__sell c3_s4('s','e','l','l') # define c3__semp c3_s4('s','e','m','p') # define c3__send c3_s4('s','e','n','d') +# define c3__sent c3_s4('s','e','n','t') # define c3__seq c3_s3('s','e','q') # define c3__serd c3_s4('s','e','r','d') # define c3__serf c3_s4('s','e','r','f') @@ -1056,6 +1072,7 @@ # define c3__shut c3_s4('s','h','u','t') # define c3__sibl c3_s4('s','i','b','l') # define c3__sift c3_s4('s','i','f','t') +# define c3__sign c3_s4('s','i','g','n') # define c3__sing c3_s4('s','i','n','g') # define c3__sist c3_s4('s','i','s','t') # define c3__site c3_s4('s','i','t','e') @@ -1232,11 +1249,13 @@ # define c3__ubin c3_s4('u','b','i','n') # define c3__ubit c3_s4('u','b','i','t') # define c3__ud c3_s2('u','d') +# define c3__uint c3_s4('u','i','n','t') # define c3__ulib c3_s4('u','l','i','b') # define c3__un c3_s2('u','n') # define c3__uniq c3_s4('u','n','i','q') # define c3__unix c3_s4('u','n','i','x') # define c3__unt c3_s3('u','n','t') +# define c3__unum c3_s3('u','n','u','m') # define c3__up c3_s2('u','p') # define c3__url c3_s3('u','r','l') # define c3__urth c3_s4('u','r','t','h') @@ -1258,6 +1277,7 @@ # define c3__vent c3_s4('v','e','n','t') # define c3__verb c3_s4('v','e','r','b') # define c3__vere c3_s4('v','e','r','e') +# define c3__veri c3_s4('v','e','r','i') # define c3__vern c3_s4('v','e','r','n') # define c3__very c3_s4('v','e','r','y') # define c3__view c3_s4('v','i','e','w') @@ -1321,6 +1341,9 @@ # define c3__wyp c3_s3('w','y','p') # define c3__wyrd c3_s4('w','y','r','d') # define c3__xray c3_s4('x','r','a','y') +# define c3__xmas c3_s4('x','m','a','s') +# define c3__x c3_s1('x') +# define c3__xx c3_s2('x','x') # define c3__yell c3_s4('y','e','l','l') # define c3__yelp c3_s4('y','e','l','p') # define c3__z c3_s1('z') diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index eaa1527e61..3e00f21f19 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -2006,9 +2006,8 @@ u3a_maid(FILE* fil_u, c3_c* cap_c, c3_w wor_w) /* _ca_print_memory(): un-captioned u3a_print_memory(). */ static void -_ca_print_memory(FILE* fil_u, c3_w wor_w) +_ca_print_memory(FILE* fil_u, c3_w byt_w) { - c3_w byt_w = (wor_w * 4); c3_w gib_w = (byt_w / 1000000000); c3_w mib_w = (byt_w % 1000000000) / 1000000; c3_w kib_w = (byt_w % 1000000) / 1000; @@ -2029,43 +2028,55 @@ _ca_print_memory(FILE* fil_u, c3_w wor_w) } } +/* u3a_quac_free: free quac memory. +*/ +void +u3a_quac_free(u3m_quac* qua_u) +{ + c3_w i_w = 0; + while ( qua_u->qua_u[i_w] != NULL ) { + u3a_quac_free(qua_u->qua_u[i_w]); + i_w++; + } + c3_free(qua_u->nam_c); + c3_free(qua_u->qua_u); + c3_free(qua_u); +} + /* u3a_prof(): mark/measure/print memory profile. RETAIN. */ -c3_w -u3a_prof(FILE* fil_u, c3_w den_w, u3_noun mas) +u3m_quac* +u3a_prof(FILE* fil_u, u3_noun mas) { - c3_w tot_w = 0; + u3m_quac* pro_u = c3_calloc(sizeof(*pro_u)); u3_noun h_mas, t_mas; if ( c3n == u3r_cell(mas, &h_mas, &t_mas) ) { - fprintf(fil_u, "%.*smistyped mass\r\n", den_w, ""); - return tot_w; + fprintf(fil_u, "mistyped mass\r\n"); + c3_free(pro_u); + return NULL; } - else if ( _(u3du(h_mas)) ) { - fprintf(fil_u, "%.*smistyped mass head\r\n", den_w, ""); + else if ( c3y == u3du(h_mas) ) { + fprintf(fil_u, "mistyped mass head\r\n"); { c3_c* lab_c = u3m_pretty(h_mas); fprintf(fil_u, "h_mas: %s", lab_c); c3_free(lab_c); } - return tot_w; + c3_free(pro_u); + return NULL; } else { - { - c3_c* lab_c = u3m_pretty(h_mas); - fprintf(fil_u, "%*s%s: ", den_w, "", lab_c); - c3_free(lab_c); - } u3_noun it_mas, tt_mas; if ( c3n == u3r_cell(t_mas, &it_mas, &tt_mas) ) { - fprintf(fil_u, "%*smistyped mass tail\r\n", den_w, ""); - return tot_w; + fprintf(fil_u, "mistyped mass tail\r\n"); + c3_free(pro_u); + return NULL; } else if ( c3y == it_mas ) { - tot_w += u3a_mark_noun(tt_mas); - _ca_print_memory(fil_u, tot_w); + c3_w siz_w = u3a_mark_noun(tt_mas); #if 1 /* The basic issue here is that tt_mas is included in .sac @@ -2076,7 +2087,7 @@ u3a_prof(FILE* fil_u, c3_w den_w, u3_noun mas) * * see u3a_mark_ptr(). */ - if ( _(u3a_is_dog(tt_mas)) ) { + if ( c3y == u3a_is_dog(tt_mas) ) { u3a_box* box_u = u3a_botox(u3a_to_ptr(tt_mas)); #ifdef U3_MEMORY_DEBUG if ( 1 == box_u->eus_w ) { @@ -2095,45 +2106,131 @@ u3a_prof(FILE* fil_u, c3_w den_w, u3_noun mas) #endif } #endif + pro_u->nam_c = u3r_string(h_mas); + pro_u->siz_w = siz_w*4; + pro_u->qua_u = NULL; + return pro_u; - return tot_w; } else if ( c3n == it_mas ) { - fprintf(fil_u, "\r\n"); - - while ( _(u3du(tt_mas)) ) { - tot_w += u3a_prof(fil_u, den_w+2, u3h(tt_mas)); + pro_u->qua_u = c3_malloc(sizeof(pro_u->qua_u)); + c3_w i_w = 0; + c3_t bad_t = 0; + while ( c3y == u3du(tt_mas) ) { + u3m_quac* new_u = u3a_prof(fil_u, u3h(tt_mas)); + if ( NULL == new_u ) { + bad_t = 1; + } else { + pro_u->qua_u = c3_realloc(pro_u->qua_u, (i_w + 2) * sizeof(pro_u->qua_u)); + pro_u->siz_w += new_u->siz_w; + pro_u->qua_u[i_w] = new_u; + } tt_mas = u3t(tt_mas); + i_w++; } + pro_u->qua_u[i_w] = NULL; - fprintf(fil_u, "%*s--", den_w, ""); - _ca_print_memory(fil_u, tot_w); - - return tot_w; - + if ( bad_t ) { + i_w = 0; + while ( pro_u->qua_u[i_w] != NULL ) { + u3a_quac_free(pro_u->qua_u[i_w]); + i_w++; + } + c3_free(pro_u->qua_u); + c3_free(pro_u); + return NULL; + } else { + pro_u->nam_c = u3r_string(h_mas); + return pro_u; + } } else { - fprintf(fil_u, "%*smistyped (strange) mass tail\r\n", den_w, ""); - return tot_w; + fprintf(fil_u, "mistyped (strange) mass tail\r\n"); + c3_free(pro_u); + return NULL; + } + } +} + + +/* u3a_print_quac: print a memory report. +*/ + +void +u3a_print_quac(FILE* fil_u, c3_w den_w, u3m_quac* mas_u) +{ + u3_assert( 0 != fil_u ); + + if ( mas_u->siz_w ) { + fprintf(fil_u, "%*s%s: ", den_w, "", mas_u->nam_c); + + if ( mas_u->qua_u == NULL ) { + _ca_print_memory(fil_u, mas_u->siz_w); + } else { + fprintf(fil_u, "\r\n"); + c3_w i_w = 0; + while ( mas_u->qua_u[i_w] != NULL ) { + u3a_print_quac(fil_u, den_w+2, mas_u->qua_u[i_w]); + i_w++; + } + fprintf(fil_u, "%*s--", den_w, ""); + _ca_print_memory(fil_u, mas_u->siz_w); } } } /* u3a_mark_road(): mark ad-hoc persistent road structures. */ -c3_w -u3a_mark_road(FILE* fil_u) -{ - c3_w tot_w = 0; - tot_w += u3a_maid(fil_u, " namespace", u3a_mark_noun(u3R->ski.gul)); - tot_w += u3a_maid(fil_u, " trace stack", u3a_mark_noun(u3R->bug.tax)); - tot_w += u3a_maid(fil_u, " trace buffer", u3a_mark_noun(u3R->bug.mer)); - tot_w += u3a_maid(fil_u, " profile batteries", u3a_mark_noun(u3R->pro.don)); - tot_w += u3a_maid(fil_u, " profile doss", u3a_mark_noun(u3R->pro.day)); - tot_w += u3a_maid(fil_u, " new profile trace", u3a_mark_noun(u3R->pro.trace)); - tot_w += u3a_maid(fil_u, " transient memoization cache", u3h_mark(u3R->cax.har_p)); - tot_w += u3a_maid(fil_u, " persistent memoization cache", u3h_mark(u3R->cax.per_p)); - return u3a_maid(fil_u, "total road stuff", tot_w); +u3m_quac* +u3a_mark_road() +{ + u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 9); + + qua_u[0] = c3_calloc(sizeof(*qua_u[0])); + qua_u[0]->nam_c = strdup("namespace"); + qua_u[0]->siz_w = u3a_mark_noun(u3R->ski.gul) * 4; + + qua_u[1] = c3_calloc(sizeof(*qua_u[1])); + qua_u[1]->nam_c = strdup("trace stack"); + qua_u[1]->siz_w = u3a_mark_noun(u3R->bug.tax) * 4; + + qua_u[2] = c3_calloc(sizeof(*qua_u[2])); + qua_u[2]->nam_c = strdup("trace buffer"); + qua_u[2]->siz_w = u3a_mark_noun(u3R->bug.mer) * 4; + + qua_u[3] = c3_calloc(sizeof(*qua_u[3])); + qua_u[3]->nam_c = strdup("profile batteries"); + qua_u[3]->siz_w = u3a_mark_noun(u3R->pro.don) * 4; + + qua_u[4] = c3_calloc(sizeof(*qua_u[4])); + qua_u[4]->nam_c = strdup("profile doss"); + qua_u[4]->siz_w = u3a_mark_noun(u3R->pro.day) * 4; + + qua_u[5] = c3_calloc(sizeof(*qua_u[5])); + qua_u[5]->nam_c = strdup("new profile trace"); + qua_u[5]->siz_w = u3a_mark_noun(u3R->pro.trace) * 4; + + qua_u[6] = c3_calloc(sizeof(*qua_u[6])); + qua_u[6]->nam_c = strdup("transient memoization cache"); + qua_u[6]->siz_w = u3h_mark(u3R->cax.har_p) * 4; + + qua_u[7] = c3_calloc(sizeof(*qua_u[7])); + qua_u[7]->nam_c = strdup("persistent memoization cache"); + qua_u[7]->siz_w = u3h_mark(u3R->cax.per_p) * 4; + + qua_u[8] = NULL; + + c3_w sum_w = 0; + for (c3_w i_w = 0; i_w < 8; i_w++) { + sum_w += qua_u[i_w]->siz_w; + } + + u3m_quac* tot_u = c3_malloc(sizeof(*tot_u)); + tot_u->nam_c = strdup("total road stuff"); + tot_u->siz_w = sum_w; + tot_u->qua_u = qua_u; + + return tot_u; } /* u3a_reclaim(): clear ad-hoc persistent caches to reclaim memory. diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index 0fa78cdaf2..3f71f42343 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -606,8 +606,8 @@ /* u3a_mark_road(): mark ad-hoc persistent road structures. */ - c3_w - u3a_mark_road(FILE* fil_u); + u3m_quac* + u3a_mark_road(); /* u3a_reclaim(): clear ad-hoc persistent caches to reclaim memory. */ @@ -702,21 +702,35 @@ void u3a_print_time(c3_c* str_c, c3_c* cap_c, c3_d mic_d); + /* u3a_print_quac: print a quac memory report. + */ + void + u3a_print_quac(FILE* fil_u, c3_w den_w, u3m_quac* mas_u); + /* u3a_print_memory(): print memory amount. */ void u3a_print_memory(FILE* fil_u, c3_c* cap_c, c3_w wor_w); - /* u3a_prof(): mark/measure/print memory profile. RETAIN. */ - c3_w - u3a_prof(FILE* fil_u, c3_w den_w, u3_noun mas); + u3m_quac* + u3a_prof(FILE* fil_u, u3_noun mas); /* u3a_maid(): maybe print memory. */ c3_w u3a_maid(FILE* fil_u, c3_c* cap_c, c3_w wor_w); + /* u3a_quac_free(): free quac memory. + */ + void + u3a_quac_free(u3m_quac* qua_u); + + /* u3a_uncap_print_memory(): un-captioned print memory amount. + */ + void + u3a_uncap_print_memory(FILE* fil_u, c3_w byt_w); + /* u3a_deadbeef(): write 0xdeadbeef from hat to cap. */ void diff --git a/pkg/noun/hashtable.c b/pkg/noun/hashtable.c index 145464e7af..961df703b6 100644 --- a/pkg/noun/hashtable.c +++ b/pkg/noun/hashtable.c @@ -15,9 +15,12 @@ */ #define BIT_SET(a_w, b_w) ((a_w) & ((c3_w)1 << (b_w))) -static c3_o +static u3_weak _ch_trim_slot(u3h_root* har_u, u3h_slot *sot_w, c3_w lef_w, c3_w rem_w); +static u3_weak +_ch_trim_root(u3h_root* har_u); + c3_w _ch_skip_slot(c3_w mug_w, c3_w lef_w); @@ -54,7 +57,7 @@ u3h_new(void) static c3_w _ch_popcount(c3_w num_w) { - return __builtin_popcount(num_w); + return c3_pc_w(num_w); } /* _ch_buck_new(): create new bucket. @@ -243,12 +246,12 @@ _ch_slot_put(u3h_slot* sot_w, u3_noun kev, c3_w lef_w, c3_w rem_w, c3_w* use_w) } } -/* u3h_put(): insert in hashtable. +/* u3h_put_get(): insert in caching hashtable, returning deleted key-value pair ** ** `key` is RETAINED; `val` is transferred. */ -void -u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val) +u3_weak +u3h_put_get(u3p(u3h_root) har_p, u3_noun key, u3_noun val) { u3h_root* har_u = u3to(u3h_root, har_p); u3_noun kev = u3nc(u3k(key), val); @@ -265,8 +268,173 @@ u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val) _ch_slot_put(sot_w, kev, 25, rem_w, &(har_u->use_w)); } - if ( har_u->max_w > 0 ) { - u3h_trim_to(har_p, har_u->max_w); + { + u3_weak ret = u3_none; + + if ( har_u->max_w && (har_u->use_w > har_u->max_w) ) { + do { + ret = _ch_trim_root(har_u); + } + while ( u3_none == ret ); + har_u->use_w -= 1; + } + + return ret; + } +} + +/* u3h_put(): insert in hashtable. +** +** `key` is RETAINED; `val` is transferred. +*/ +void +u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val) +{ + u3_weak del = u3h_put_get(har_p, key, val); + if ( u3_none != del ) { + u3z(del); + } +} + +/* _ch_buck_del(): delete from bucket +*/ +static c3_o +_ch_buck_del(u3h_slot* sot_w, u3_noun key) +{ + u3h_buck* hab_u = u3h_slot_to_node(*sot_w); + c3_w fin_w = hab_u->len_w; + c3_w i_w; + // + // find index of key to be deleted + // + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + u3_noun kov = u3h_slot_to_noun(hab_u->sot_w[i_w]); + if ( c3y == u3r_sing(key, u3h(kov)) ) { + fin_w = i_w; + u3z(kov); + break; + } + } + + // no key found, no-op + if ( fin_w == hab_u->len_w ) { + return c3n; + } + + { + hab_u->len_w--; + // u3_assert(c3y == u3h_slot_is_noun(hab_u->sot_w[fin_w])); + for ( i_w = fin_w; i_w < hab_u->len_w; i_w++ ) { + hab_u->sot_w[i_w] = hab_u->sot_w[i_w + 1]; + } + + return c3y; + } +} + +static c3_o _ch_some_del(u3h_slot*, u3_noun, c3_w, c3_w); + +/* _ch_slot_del(): delete from slot +*/ +static c3_o +_ch_slot_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w) +{ + if ( c3y == u3h_slot_is_noun(*sot_w) ) { + u3_noun kev = u3h_slot_to_noun(*sot_w); + *sot_w = 0; + u3z(kev); + return c3y; + } + else { + return _ch_some_del(sot_w, key, lef_w, rem_w); + } +} + +/* _ch_slot_del(): delete from node +*/ +static c3_o +_ch_node_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w) +{ + u3h_node* han_u = (u3h_node*) u3h_slot_to_node(*sot_w); + u3h_slot* tos_w; + + c3_w bit_w, inx_w, map_w, i_w; + + lef_w -= 5; + bit_w = (rem_w >> lef_w); + rem_w = CUT_END(rem_w, lef_w); + map_w = han_u->map_w; + inx_w = _ch_popcount(CUT_END(map_w, bit_w)); + + tos_w = &(han_u->sot_w[inx_w]); + + // nothing at slot, no-op + if ( !BIT_SET(map_w, bit_w) ) { + return c3n; + } + + if ( c3n == _ch_slot_del(tos_w, key, lef_w, rem_w) ) { + // nothing deleted + return c3n; + } + else if ( 0 != *tos_w ) { + // something deleted, but slot still has value + return c3y; + } + else { + // shrink! + c3_w i_w, ken_w, len_w = _ch_popcount(map_w); + u3h_slot kes_w; + + if ( 2 == len_w && ((ken_w = (0 == inx_w) ? 1 : 0), + (kes_w = han_u->sot_w[ken_w]), + (c3y == u3h_slot_is_noun(kes_w))) ) + { + // only one side left, and the other is a noun. debucketize. + *sot_w = kes_w; + u3a_wfree(han_u); + } + else { + // shrink node in place; don't reallocate, we could be low on memory + // + han_u->map_w &= ~(1 << bit_w); + --len_w; + + for ( i_w = inx_w; i_w < len_w; i_w++ ) { + han_u->sot_w[i_w] = han_u->sot_w[i_w + 1]; + } + } + return c3y; + } +} + +/* _ch_some_del(): delete from node or buck +*/ +static c3_o +_ch_some_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w) +{ + if ( 0 == lef_w ) { + return _ch_buck_del(sot_w, key); + } + + return _ch_node_del(sot_w, key, lef_w, rem_w); +} + +/* u3h_del(); delete from hashtable. +*/ +void +u3h_del(u3p(u3h_root) har_p, u3_noun key) +{ + u3h_root* har_u = u3to(u3h_root, har_p); + c3_w mug_w = u3r_mug(key); + c3_w inx_w = (mug_w >> 25); + c3_w rem_w = CUT_END(mug_w, 25); + u3h_slot* sot_w = &(har_u->sot_w[inx_w]); + + if ( (c3n == u3h_slot_is_null(*sot_w)) + && (c3y == _ch_slot_del(sot_w, key, 25, rem_w)) ) + { + har_u->use_w--; } } @@ -292,7 +460,7 @@ u3h_uni(u3p(u3h_root) har_p, u3p(u3h_root) rah_p) /* _ch_trim_node(): trim one entry from a node slot or its children */ -static c3_o +static u3_weak _ch_trim_node(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w) { c3_w bit_w, map_w, inx_w; @@ -312,15 +480,8 @@ _ch_trim_node(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w) inx_w = _ch_popcount(CUT_END(map_w, bit_w)); tos_w = &(han_u->sot_w[inx_w]); - if ( c3n == _ch_trim_slot(har_u, tos_w, lef_w, rem_w) ) { - // nothing trimmed - return c3n; - } - else if ( 0 != *tos_w ) { - // something trimmed, but slot still has value - return c3y; - } - else { + u3_weak ret = _ch_trim_slot(har_u, tos_w, lef_w, rem_w); + if ( (u3_none != ret) && (0 == *tos_w) ) { // shrink! c3_w i_w, ken_w, len_w = _ch_popcount(map_w); u3h_slot kes_w; @@ -342,30 +503,29 @@ _ch_trim_node(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w) han_u->sot_w[i_w] = han_u->sot_w[i_w + 1]; } } - return c3y; } + return ret; } /* _ch_trim_kev(): trim a single entry slot */ -static c3_o +static u3_weak _ch_trim_kev(u3h_slot *sot_w) { if ( _(u3h_slot_is_warm(*sot_w)) ) { *sot_w = u3h_noun_be_cold(*sot_w); - return c3n; + return u3_none; } else { u3_noun kev = u3h_slot_to_noun(*sot_w); *sot_w = 0; - u3z(kev); - return c3y; + return kev; } } /* _ch_trim_node(): trim one entry from a bucket slot */ -static c3_o +static u3_weak _ch_trim_buck(u3h_root* har_u, u3h_slot* sot_w) { c3_w i_w, len_w; @@ -375,7 +535,8 @@ _ch_trim_buck(u3h_root* har_u, u3h_slot* sot_w) har_u->arm_u.inx_w < len_w; har_u->arm_u.inx_w += 1 ) { - if ( c3y == _ch_trim_kev(&(hab_u->sot_w[har_u->arm_u.inx_w])) ) { + u3_weak ret = _ch_trim_kev(&(hab_u->sot_w[har_u->arm_u.inx_w])); + if ( u3_none != ret ) { if ( 2 == len_w ) { // 2 things in bucket: debucketize to key-value pair, the next // run will point at this pair (same mug_w, no longer in bucket) @@ -393,18 +554,18 @@ _ch_trim_buck(u3h_root* har_u, u3h_slot* sot_w) // leave the arm pointing at the next index in the bucket ++(har_u->arm_u.inx_w); } - return c3y; + return ret; } } har_u->arm_u.mug_w = (har_u->arm_u.mug_w + 1) & 0x7FFFFFFF; // modulo 2^31 har_u->arm_u.inx_w = 0; - return c3n; + return u3_none; } /* _ch_trim_some(): trim one entry from a bucket or node slot */ -static c3_o +static u3_weak _ch_trim_some(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w) { if ( 0 == lef_w ) { @@ -427,7 +588,7 @@ _ch_skip_slot(c3_w mug_w, c3_w lef_w) /* _ch_trim_slot(): trim one entry from a non-bucket slot */ -static c3_o +static u3_weak _ch_trim_slot(u3h_root* har_u, u3h_slot *sot_w, c3_w lef_w, c3_w rem_w) { if ( c3y == u3h_slot_is_noun(*sot_w) ) { @@ -441,7 +602,7 @@ _ch_trim_slot(u3h_root* har_u, u3h_slot *sot_w, c3_w lef_w, c3_w rem_w) /* _ch_trim_root(): trim one entry from a hashtable */ -static c3_o +static u3_weak _ch_trim_root(u3h_root* har_u) { c3_w mug_w = har_u->arm_u.mug_w; @@ -450,7 +611,7 @@ _ch_trim_root(u3h_root* har_u) if ( c3y == u3h_slot_is_null(*sot_w) ) { har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, 25); - return c3n; + return u3_none; } return _ch_trim_slot(har_u, sot_w, 25, CUT_END(mug_w, 25)); @@ -460,12 +621,22 @@ _ch_trim_root(u3h_root* har_u) */ void u3h_trim_to(u3p(u3h_root) har_p, c3_w n_w) +{ + u3h_trim_with(har_p, n_w, u3a_lose); +} + +/* u3h_trim_to(): trim to n key-value pairs +*/ +void +u3h_trim_with(u3p(u3h_root) har_p, c3_w n_w, void (*del_cb)(u3_noun)) { u3h_root* har_u = u3to(u3h_root, har_p); while ( har_u->use_w > n_w ) { - if ( c3y == _ch_trim_root(har_u) ) { + u3_weak del = _ch_trim_root(har_u); + if ( u3_none != del ) { har_u->use_w -= 1; + del_cb(del); } } } @@ -667,6 +838,7 @@ u3h_get(u3p(u3h_root) har_p, u3_noun key) static void _ch_free_buck(u3h_buck* hab_u) { + //fprintf(stderr, "free buck\r\n"); c3_w i_w; for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { @@ -678,7 +850,7 @@ _ch_free_buck(u3h_buck* hab_u) /* _ch_free_node(): free node. */ static void -_ch_free_node(u3h_node* han_u, c3_w lef_w) +_ch_free_node(u3h_node* han_u, c3_w lef_w, c3_o pin_o) { c3_w len_w = _ch_popcount(han_u->map_w); c3_w i_w; @@ -687,17 +859,16 @@ _ch_free_node(u3h_node* han_u, c3_w lef_w) for ( i_w = 0; i_w < len_w; i_w++ ) { c3_w sot_w = han_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { + if ( _(u3h_slot_is_null(sot_w))) { + } else if ( _(u3h_slot_is_noun(sot_w)) ) { u3z(u3h_slot_to_noun(sot_w)); - } - else { + } else { void* hav_v = u3h_slot_to_node(sot_w); if ( 0 == lef_w ) { _ch_free_buck(hav_v); } else { - _ch_free_node(hav_v, lef_w); + _ch_free_node(hav_v, lef_w, pin_o); } } } @@ -721,7 +892,7 @@ u3h_free(u3p(u3h_root) har_p) else if ( _(u3h_slot_is_node(sot_w)) ) { u3h_node* han_u = u3h_slot_to_node(sot_w); - _ch_free_node(han_u, 25); + _ch_free_node(han_u, 25, i_w == 57); } } u3a_wfree(har_u); diff --git a/pkg/noun/hashtable.h b/pkg/noun/hashtable.h index 50daba911f..75c6ab5a21 100644 --- a/pkg/noun/hashtable.h +++ b/pkg/noun/hashtable.h @@ -106,6 +106,13 @@ void u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val); + /* u3h_put_get(): insert in caching hashtable, returning deleted entry + ** + ** `key` is RETAINED; `val` is transferred. + */ + u3_weak + u3h_put_get(u3p(u3h_root) har_p, u3_noun key, u3_noun val); + /* u3h_uni(): unify hashtables, copying [rah_p] into [har_p] */ void @@ -125,11 +132,23 @@ u3_weak u3h_git(u3p(u3h_root) har_p, u3_noun key); + /* u3h_del(); delete from hashtable. + ** + ** `key` is RETAINED + */ + void + u3h_del(u3p(u3h_root) har_p, u3_noun key); + /* u3h_trim_to(): trim to n key-value pairs */ void u3h_trim_to(u3p(u3h_root) har_p, c3_w n_w); + /* u3h_trim_with(): trim to n key-value pairs, with deletion callback + */ + void + u3h_trim_with(u3p(u3h_root) har_p, c3_w n_w, void (*del_cb)(u3_noun)); + /* u3h_free(): free hashtable. */ void diff --git a/pkg/noun/hashtable_tests.c b/pkg/noun/hashtable_tests.c index 36afc07b2c..9a5a3f8ada 100644 --- a/pkg/noun/hashtable_tests.c +++ b/pkg/noun/hashtable_tests.c @@ -1,6 +1,7 @@ /// @file #include "noun.h" +#define TEST_SIZE 100000 // defined in noun/hashtable.c c3_w _ch_skip_slot(c3_w mug_w, c3_w lef_w); @@ -10,10 +11,63 @@ c3_w _ch_skip_slot(c3_w mug_w, c3_w lef_w); static void _setup(void) { - u3m_init(1 << 26); + u3m_init(1 << 27); u3m_pave(c3y); } +/* _test_put_del(): +*/ +static c3_i +_test_put_del() +{ + u3p(u3h_root) har_p = u3h_new(); + c3_i ret_i = 1; + + c3_w i_w; + for ( i_w = 0; i_w < TEST_SIZE; i_w++ ) { + u3_noun key = u3i_word(i_w); + u3_noun val = u3nc(u3_nul, u3k(key)); + u3h_put(har_p, key, val); + u3z(key); + } + // fprintf(stderr, "inserted\r\n"); + + for ( i_w = 0; i_w < TEST_SIZE; i_w++ ) { + u3_noun key = u3i_word(i_w); + u3_weak val = u3h_get(har_p, key); + if ( val == u3_none ) { + fprintf(stderr, "failed insert\r\n"); + ret_i = 0; + } + u3z(key); + u3z(val); + } + // fprintf(stderr, "presence\r\n"); + c3_w del_w[4] = {30, 82, 4921, 535}; + + for ( i_w = 0; i_w < 4; i_w++ ) { + u3_noun key = u3i_word(del_w[i_w]); + u3h_del(har_p, key); + u3z(key); + } + // fprintf(stderr, "deleted\r\n"); + + for ( i_w = 0; i_w < 4; i_w++ ) { + u3_noun key = u3i_word(del_w[i_w]); + u3_weak val = u3h_get(har_p, key); + if ( u3_none != val ) { + fprintf(stderr, "failed delete\r\n"); + ret_i = 0; + break; + } + } + // fprintf(stderr, "presence two\r\n"); + u3h_free(har_p); + // fprintf(stderr, "freed\r\n"); + + return ret_i; +} + /* _test_bit_manipulation(): */ static c3_i @@ -220,6 +274,7 @@ _test_hashtable(void) ret_i &= _test_skip_slot(); ret_i &= _test_cache_trimming(); ret_i &= _test_cache_replace_value(); + ret_i &= _test_put_del(); return ret_i; } diff --git a/pkg/noun/jets.c b/pkg/noun/jets.c index 52e72b340d..200f7d46ef 100644 --- a/pkg/noun/jets.c +++ b/pkg/noun/jets.c @@ -2305,27 +2305,61 @@ _cj_mark_hank(u3_noun kev, void* dat) /* u3j_mark(): mark jet state for gc. */ -c3_w -u3j_mark(FILE* fil_u) +u3m_quac* +u3j_mark() { - c3_w tot_w = 0; + u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 7); - tot_w += u3a_maid(fil_u, " warm jet state", u3h_mark(u3R->jed.war_p)); - tot_w += u3a_maid(fil_u, " cold jet state", u3h_mark(u3R->jed.cod_p)); - tot_w += u3a_maid(fil_u, " hank cache", u3h_mark(u3R->jed.han_p)); - tot_w += u3a_maid(fil_u, " battery hash cache", u3h_mark(u3R->jed.bas_p)); + qua_u[0] = c3_calloc(sizeof(*qua_u[0])); + qua_u[0]->nam_c = strdup("warm jet state"); + qua_u[0]->siz_w = u3h_mark(u3R->jed.war_p) * 4; - { - c3_w han_w = 0; - u3h_walk_with(u3R->jed.han_p, _cj_mark_hank, &han_w); - tot_w += u3a_maid(fil_u, " call site cache", han_w); + qua_u[1] = c3_calloc(sizeof(*qua_u[1])); + qua_u[1]->nam_c = strdup("cold jet state"); + qua_u[1]->siz_w = u3h_mark(u3R->jed.cod_p) * 4; + + qua_u[2] = c3_calloc(sizeof(*qua_u[2])); + qua_u[2]->nam_c = strdup("hank cache"); + qua_u[2]->siz_w = u3h_mark(u3R->jed.han_p) * 4; + + qua_u[3] = c3_calloc(sizeof(*qua_u[3])); + qua_u[3]->nam_c = strdup("battery hash cache"); + qua_u[3]->siz_w = u3h_mark(u3R->jed.bas_p) * 4; + + qua_u[4] = c3_calloc(sizeof(*qua_u[4])); + qua_u[4]->nam_c = strdup("call site cache"); + u3h_walk_with(u3R->jed.han_p, _cj_mark_hank, &qua_u[4]->siz_w); + qua_u[4]->siz_w *= 4; + + c3_w sum_w = 0; + for ( c3_w i_w = 0; i_w < 5; i_w++ ) { + sum_w += qua_u[i_w]->siz_w; } + u3m_quac* tot_u = c3_calloc(sizeof(*tot_u)); + tot_u->nam_c = strdup("total jet stuff"); + if ( u3R == &(u3H->rod_u) ) { - tot_w += u3a_maid(fil_u, " hot jet state", u3h_mark(u3R->jed.hot_p)); - } + qua_u[5] = c3_calloc(sizeof(*qua_u[5])); + qua_u[5]->nam_c = strdup("hot jet state"); + qua_u[5]->siz_w = u3h_mark(u3R->jed.hot_p) * 4; + + sum_w += qua_u[5]->siz_w; + + qua_u[6] = NULL; + + tot_u->siz_w = sum_w; + tot_u->qua_u = qua_u; - return u3a_maid(fil_u, "total jet stuff", tot_w); + return tot_u; + } else { + qua_u[5] = NULL; + + tot_u->siz_w = sum_w; + tot_u->qua_u = qua_u; + + return tot_u; + } } /* u3j_free_hank(): free an entry from the hank cache. diff --git a/pkg/noun/jets.h b/pkg/noun/jets.h index bfaa68aeaa..c81ab18318 100644 --- a/pkg/noun/jets.h +++ b/pkg/noun/jets.h @@ -296,8 +296,8 @@ /* u3j_mark(): mark jet state for gc. */ - c3_w - u3j_mark(FILE* fil_u); + u3m_quac* + u3j_mark(); /* u3j_free(): free jet state. */ diff --git a/pkg/noun/jets/137/tree.c b/pkg/noun/jets/137/tree.c new file mode 100644 index 0000000000..fec03edf1f --- /dev/null +++ b/pkg/noun/jets/137/tree.c @@ -0,0 +1,1098 @@ +#include "c3/c3.h" +#include "jets.h" +#include "jets/w.h" + + +static c3_c* no_hashes[] = { 0 }; + +static u3j_harm _137_hex_mimes_base16_en_a[] = {{".2", u3we_en_base16}, {}}; +static u3j_harm _137_hex_mimes_base16_de_a[] = {{".2", u3we_de_base16}, {}}; +static u3j_core _137_hex_mimes_base16_d[] = + { { "en", 7, _137_hex_mimes_base16_en_a, 0, no_hashes }, + { "de", 7, _137_hex_mimes_base16_de_a, 0, no_hashes }, + {} + }; +static u3j_core _137_hex_mimes_d[] = + { { "base16", 3, 0, _137_hex_mimes_base16_d, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_ecba_en_a[] = {{".2", u3wea_ecba_en}, {}}; +static u3j_harm _137_hex_aes_ecba_de_a[] = {{".2", u3wea_ecba_de}, {}}; +static u3j_core _137_hex_aes_ecba_d[] = + { { "en", 7, _137_hex_aes_ecba_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_ecba_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_ecbb_en_a[] = {{".2", u3wea_ecbb_en}, {}}; +static u3j_harm _137_hex_aes_ecbb_de_a[] = {{".2", u3wea_ecbb_de}, {}}; +static u3j_core _137_hex_aes_ecbb_d[] = + { { "en", 7, _137_hex_aes_ecbb_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_ecbb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_ecbc_en_a[] = {{".2", u3wea_ecbc_en}, {}}; +static u3j_harm _137_hex_aes_ecbc_de_a[] = {{".2", u3wea_ecbc_de}, {}}; +static u3j_core _137_hex_aes_ecbc_d[] = + { { "en", 7, _137_hex_aes_ecbc_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_ecbc_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_cbca_en_a[] = {{".2", u3wea_cbca_en}, {}}; +static u3j_harm _137_hex_aes_cbca_de_a[] = {{".2", u3wea_cbca_de}, {}}; +static u3j_core _137_hex_aes_cbca_d[] = + { { "en", 7, _137_hex_aes_cbca_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_cbca_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_cbcb_en_a[] = {{".2", u3wea_cbcb_en}, {}}; +static u3j_harm _137_hex_aes_cbcb_de_a[] = {{".2", u3wea_cbcb_de}, {}}; +static u3j_core _137_hex_aes_cbcb_d[] = + { { "en", 7, _137_hex_aes_cbcb_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_cbcb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_cbcc_en_a[] = {{".2", u3wea_cbcc_en}, {}}; +static u3j_harm _137_hex_aes_cbcc_de_a[] = {{".2", u3wea_cbcc_de}, {}}; +static u3j_core _137_hex_aes_cbcc_d[] = + { { "en", 7, _137_hex_aes_cbcc_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_cbcc_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_siva_en_a[] = {{".2", u3wea_siva_en}, {}}; +static u3j_harm _137_hex_aes_siva_de_a[] = {{".2", u3wea_siva_de}, {}}; +static u3j_core _137_hex_aes_siva_d[] = + { { "en", 7, _137_hex_aes_siva_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_siva_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_sivb_en_a[] = {{".2", u3wea_sivb_en}, {}}; +static u3j_harm _137_hex_aes_sivb_de_a[] = {{".2", u3wea_sivb_de}, {}}; +static u3j_core _137_hex_aes_sivb_d[] = + { { "en", 7, _137_hex_aes_sivb_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_sivb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_sivc_en_a[] = {{".2", u3wea_sivc_en}, {}}; +static u3j_harm _137_hex_aes_sivc_de_a[] = {{".2", u3wea_sivc_de}, {}}; +static u3j_core _137_hex_aes_sivc_d[] = + { { "en", 7, _137_hex_aes_sivc_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_sivc_de_a, 0, no_hashes }, + {} + }; +static u3j_core _137_hex_aes_d[] = + { { "ecba", 7, 0, _137_hex_aes_ecba_d, no_hashes }, + { "ecbb", 7, 0, _137_hex_aes_ecbb_d, no_hashes }, + { "ecbc", 7, 0, _137_hex_aes_ecbc_d, no_hashes }, + { "cbca", 7, 0, _137_hex_aes_cbca_d, no_hashes }, + { "cbcb", 7, 0, _137_hex_aes_cbcb_d, no_hashes }, + { "cbcc", 7, 0, _137_hex_aes_cbcc_d, no_hashes }, + { "siva", 7, 0, _137_hex_aes_siva_d, no_hashes }, + { "sivb", 7, 0, _137_hex_aes_sivb_d, no_hashes }, + { "sivc", 7, 0, _137_hex_aes_sivc_d, no_hashes }, + {} + }; + +static u3j_harm _137_hex_leer_a[] = {{".2", u3we_leer}, {}}; +static u3j_harm _137_hex_lore_a[] = {{".2", u3we_lore}, {}}; +static u3j_harm _137_hex_loss_a[] = {{".2", u3we_loss}, {}}; +static u3j_harm _137_hex_lune_a[] = {{".2", u3we_lune}, {}}; + + +static u3j_harm _137_hex__crc32_a[] = {{".2", u3we_crc32}, {}}; + +static u3j_core _137_hex__crc_d[] = {{"crc32", 7, _137_hex__crc32_a, 0, no_hashes }, {}}; + + +static u3j_harm _137_hex_coed__ed_puck_a[] = {{".2", u3wee_puck}, {}}; +static u3j_harm _137_hex_coed__ed_sign_octs_a[] = {{".2", u3wee_sign_octs}, {}}; +static u3j_harm _137_hex_coed__ed_veri_octs_a[] = {{".2", u3wee_veri_octs}, {}}; +static u3j_harm _137_hex_coed__ed_shar_a[] = {{".2", u3wee_shar}, {}}; + +static u3j_harm _137_hex_coed__ed_point_add_a[] = + {{".2", u3wee_point_add}, {}}; + +static u3j_harm _137_hex_coed__ed_scalarmult_a[] = + {{".2", u3wee_scalarmult}, {}}; + +static u3j_harm _137_hex_coed__ed_scalarmult_base_a[] = + {{".2", u3wee_scalarmult_base}, {}}; + +static u3j_harm _137_hex_coed__ed_add_scalarmult_scalarmult_base_a[] = + {{".2", u3wee_add_scalarmult_scalarmult_base}, {}}; + +static u3j_harm _137_hex_coed__ed_add_double_scalarmult_a[] = + {{".2", u3wee_add_double_scalarmult}, {}}; + +static u3j_core _137_hex_coed__ed_d[] = + { { "sign-octs", 7, _137_hex_coed__ed_sign_octs_a, 0, no_hashes }, + { "puck", 7, _137_hex_coed__ed_puck_a, 0, no_hashes }, + { "veri-octs", 7, _137_hex_coed__ed_veri_octs_a, 0, no_hashes }, + { "shar", 7, _137_hex_coed__ed_shar_a, 0, no_hashes }, + { "point-add", 7, _137_hex_coed__ed_point_add_a, 0, 0 }, + { "scalarmult", 7, _137_hex_coed__ed_scalarmult_a, 0, + no_hashes }, + { "scalarmult-base", 7, _137_hex_coed__ed_scalarmult_base_a, 0, + no_hashes }, + { "add-scalarmult-scalarmult-base", 7, + _137_hex_coed__ed_add_scalarmult_scalarmult_base_a, 0, + no_hashes }, + { "add-double-scalarmult", 7, + _137_hex_coed__ed_add_double_scalarmult_a, 0, + no_hashes }, + {} + }; + +static u3j_core _137_hex_coed_d[] = + { { "ed", 3, 0, _137_hex_coed__ed_d, no_hashes }, + {} + }; + +static u3j_harm _137_hex_hmac_hmac_a[] = {{".2", u3we_hmac}, {}}; +static u3j_core _137_hex_hmac_d[] = + { { "hmac", 7, _137_hex_hmac_hmac_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_argon2_a[] = {{".2", u3we_argon2}, {}}; +static u3j_core _137_hex_argon_d[] = + { { "argon2", 511, _137_hex_argon2_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_scr_pbk_a[] = {{".2", u3wes_pbk, c3y}, {}}; +static u3j_harm _137_hex_scr_pbl_a[] = {{".2", u3wes_pbl, c3y}, {}}; +static u3j_harm _137_hex_scr_hsh_a[] = {{".2", u3wes_hsh, c3y}, {}}; +static u3j_harm _137_hex_scr_hsl_a[] = {{".2", u3wes_hsl, c3y}, {}}; +static u3j_core _137_hex_scr_d[] = + { { "pbk", 7, _137_hex_scr_pbk_a, 0, no_hashes }, + { "pbl", 7, _137_hex_scr_pbl_a, 0, no_hashes }, + { "hsh", 7, _137_hex_scr_hsh_a, 0, no_hashes }, + { "hsl", 7, _137_hex_scr_hsl_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_secp_secp256k1_make_a[] = {{".2", u3we_make, c3y}, {}}; +static u3j_harm _137_hex_secp_secp256k1_sign_a[] = {{".2", u3we_sign, c3y}, {}}; +static u3j_harm _137_hex_secp_secp256k1_reco_a[] = {{".2", u3we_reco, c3y}, {}}; + +static u3j_harm _137_hex_secp_secp256k1_schnorr_sosi_a[] = + {{".2", u3we_sosi}, {}}; +static u3j_harm _137_hex_secp_secp256k1_schnorr_sove_a[] = + {{".2", u3we_sove}, {}}; +static u3j_core _137_hex_secp_secp256k1_schnorr_d[] = + { { "sosi", 7, + _137_hex_secp_secp256k1_schnorr_sosi_a, 0, + no_hashes }, + { "sove", 7, + _137_hex_secp_secp256k1_schnorr_sove_a, 0, + no_hashes }, + {} + }; + +static u3j_core _137_hex_secp_secp256k1_d[] = + { { "make", 7, _137_hex_secp_secp256k1_make_a, 0, no_hashes }, + { "sign", 7, _137_hex_secp_secp256k1_sign_a, 0, no_hashes }, + { "reco", 7, _137_hex_secp_secp256k1_reco_a, 0, no_hashes }, + { "schnorr", 7, 0, + _137_hex_secp_secp256k1_schnorr_d, + no_hashes }, + {} + }; +static u3j_core _137_hex_secp_d[] = + { { "secp256k1", 3, 0, _137_hex_secp_secp256k1_d, no_hashes }, + {} + }; + + +static u3j_harm _137_hex_kecc_k224_a[] = + {{".2", u3we_kecc224, c3y, c3y, c3y}, {}}; +static u3j_harm _137_hex_kecc_k256_a[] = + {{".2", u3we_kecc256, c3y, c3y, c3y}, {}}; +static u3j_harm _137_hex_kecc_k384_a[] = + {{".2", u3we_kecc384, c3y, c3y, c3y}, {}}; +static u3j_harm _137_hex_kecc_k512_a[] = + {{".2", u3we_kecc512, c3y, c3y, c3y}, {}}; +static u3j_core _137_hex_kecc_d[] = + { { "k224", 7, _137_hex_kecc_k224_a, 0, no_hashes }, + { "k256", 7, _137_hex_kecc_k256_a, 0, no_hashes }, + { "k384", 7, _137_hex_kecc_k384_a, 0, no_hashes }, + { "k512", 7, _137_hex_kecc_k512_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_ripemd_160_a[] = {{".2", u3we_ripe, c3y}, {}}; +static u3j_core _137_hex_ripe_d[] = + { { "ripemd160", 7, _137_hex_ripemd_160_a, 0, no_hashes }, + {} + }; + + + +/* layer five + */ +static u3j_harm _137_pen_cell_a[] = {{".2", u3wf_cell}, {}}; +static u3j_harm _137_pen_comb_a[] = {{".2", u3wf_comb}, {}}; +static u3j_harm _137_pen_cons_a[] = {{".2", u3wf_cons}, {}}; +static u3j_harm _137_pen_core_a[] = {{".2", u3wf_core}, {}}; +static u3j_harm _137_pen_face_a[] = {{".2", u3wf_face}, {}}; +static u3j_harm _137_pen_fitz_a[] = {{".2", u3wf_fitz}, {}}; +static u3j_harm _137_pen_fork_a[] = {{".2", u3wf_fork}, {}}; + +static u3j_harm _137_pen_look_a[] = {{".2", u3wf_look}, {}}; +static u3j_harm _137_pen_loot_a[] = {{".2", u3wf_loot}, {}}; + +static u3j_harm _137_pen__ut_crop_a[] = {{".2", u3wfu_crop}, {}}; +static u3j_harm _137_pen__ut_fish_a[] = {{".2", u3wfu_fish}, {}}; +static u3j_harm _137_pen__ut_fuse_a[] = {{".2", u3wfu_fuse}, {}}; +static u3j_harm _137_pen__ut_mint_a[] = {{".2", u3wfu_mint}, {}}; +static u3j_harm _137_pen__ut_mull_a[] = {{".2", u3wfu_mull}, {}}; + +static u3j_harm _137_pen__ut_nest_dext_a[] = {{".2", u3wfu_nest_dext}, {}}; +static u3j_core _137_pen__ut_nest_in_d[] = + { + { "nest-dext", 3, _137_pen__ut_nest_dext_a, 0, no_hashes }, + {} + }; +static u3j_core _137_pen__ut_nest_d[] = + { + { "nest-in", 7, 0, _137_pen__ut_nest_in_d, no_hashes }, + {} + }; + +static u3j_harm _137_pen__ut_rest_a[] = {{".2", u3wfu_rest}, {}}; + +static u3j_core _137_pen__ut_d[] = + { + { "crop", 7, _137_pen__ut_crop_a, 0, no_hashes }, + { "fish", 7, _137_pen__ut_fish_a, 0, no_hashes }, + { "fuse", 7, _137_pen__ut_fuse_a, 0, no_hashes }, + { "mint", 7, _137_pen__ut_mint_a, 0, no_hashes }, + { "mull", 7, _137_pen__ut_mull_a, 0, no_hashes }, + { "nest", 7, 0, _137_pen__ut_nest_d, no_hashes }, + { "rest", 7, _137_pen__ut_rest_a, 0, no_hashes }, + {} + }; + +static u3j_hood _137_pen__ut_ho[] = + { { "ar", 12282 }, + { "fan", 28, c3n }, + { "rib", 58, c3n }, + { "vet", 59, c3n }, + + { "blow", 6015 }, + { "burp", 342 }, + { "busk", 1373 }, + { "buss", 374 }, + { "crop", 1494 }, + { "duck", 1524 }, + { "dune", 2991 }, + { "dunk", 3066 }, + { "epla", 12206 }, + { "emin", 1534 }, + { "emul", 6134 }, + { "feel", 1502 }, + { "felt", 94 }, + { "fine", 49086 }, + { "fire", 4 }, + { "fish", 6006 }, + { "fond", 12283 }, + { "fund", 6014 }, + // XX +funk is not part of +ut, and this hook appears to be unused + // remove from here and the +ut hint + // + { "funk", 0xbefafa, c3y, 31 }, + { "fuse", 24021 }, + { "gain", 380 }, + { "lose", 0x2fefe }, + { "mile", 382 }, + { "mine", 372 }, + { "mint", 49083 }, + { "moot", 0x2feff }, + { "mull", 24020 }, + { "nest", 92 }, + { "peel", 1526 }, + { "play", 3006 }, + { "peek", 1532 }, + { "repo", 22 }, + { "rest", 6102 }, + { "tack", 6007 }, + { "toss", 24540 }, + { "wrap", 6137 }, + {}, + }; + + +static u3j_hood _137_pen_ho[] = { + { "ap", 22 }, + { "ut", 86 }, + {}, +}; + + +/* layer four + */ +static u3j_harm _137_qua_trip_a[] = {{".2", u3we_trip}, {}}; + +static u3j_harm _137_qua_slaw_a[] = {{".2", u3we_slaw}, {}}; +static u3j_harm _137_qua_scot_a[] = {{".2", u3we_scot}, {}}; +static u3j_harm _137_qua_scow_a[] = {{".2", u3we_scow}, {}}; + +static u3j_harm _137_qua__po_ind_a[] = {{".2", u3wcp_ind}, {}}; +static u3j_harm _137_qua__po_ins_a[] = {{".2", u3wcp_ins}, {}}; +static u3j_harm _137_qua__po_tod_a[] = {{".2", u3wcp_tod}, {}}; +static u3j_harm _137_qua__po_tos_a[] = {{".2", u3wcp_tos}, {}}; +static u3j_core _137_qua__po_d[] = + { { "ind", 7, _137_qua__po_ind_a, 0, no_hashes }, + { "ins", 7, _137_qua__po_ins_a, 0, no_hashes }, + { "tod", 7, _137_qua__po_tod_a, 0, no_hashes }, + { "tos", 7, _137_qua__po_tos_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__bend_fun_a[] = {{".2", u3we_bend_fun}, {}}; +static u3j_core _137_qua__bend_d[] = + { { "fun", 7, _137_qua__bend_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__cold_fun_a[] = {{".2", u3we_cold_fun}, {}}; +static u3j_core _137_qua__cold_d[] = + { { "fun", 7, _137_qua__cold_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__cook_fun_a[] = {{".2", u3we_cook_fun}, {}}; +static u3j_core _137_qua__cook_d[] = + { { "fun", 7, _137_qua__cook_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__comp_fun_a[] = {{".2", u3we_comp_fun}, {}}; +static u3j_core _137_qua__comp_d[] = + { { "fun", 7, _137_qua__comp_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__easy_fun_a[] = {{".2", u3we_easy_fun}, {}}; +static u3j_core _137_qua__easy_d[] = + { { "fun", 7, _137_qua__easy_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__glue_fun_a[] = {{".2", u3we_glue_fun}, {}}; +static u3j_core _137_qua__glue_d[] = + { { "fun", 7, _137_qua__glue_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__here_fun_a[] = {{".2", u3we_here_fun}, {}}; +static u3j_core _137_qua__here_d[] = + { { "fun", 7, _137_qua__here_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__just_fun_a[] = {{".2", u3we_just_fun}, {}}; +static u3j_core _137_qua__just_d[] = + { { "fun", 7, _137_qua__just_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__mask_fun_a[] = {{".2", u3we_mask_fun}, {}}; +static u3j_core _137_qua__mask_d[] = + { { "fun", 7, _137_qua__mask_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__shim_fun_a[] = {{".2", u3we_shim_fun}, {}}; +static u3j_core _137_qua__shim_d[] = + { { "fun", 7, _137_qua__shim_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__stag_fun_a[] = {{".2", u3we_stag_fun}, {}}; +static u3j_core _137_qua__stag_d[] = + { { "fun", 7, _137_qua__stag_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__stew_fun_a[] = {{".2", u3we_stew_fun}, {}}; +static u3j_core _137_qua__stew_d[] = + { { "fun", 31, _137_qua__stew_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__stir_fun_a[] = {{".2", u3we_stir_fun}, {}}; +static u3j_core _137_qua__stir_d[] = + { { "fun", 7, _137_qua__stir_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua_pfix_a[] = {{".2", u3we_pfix}, {}}; + +static u3j_harm _137_qua_plug_a[] = {{".2", u3we_plug}, {}}; +static u3j_harm _137_qua_pose_a[] = {{".2", u3we_pose}, {}}; + +static u3j_harm _137_qua_sfix_a[] = {{".2", u3we_sfix}, {}}; + +static u3j_harm _137_qua_mink_a[] = {{".2", u3we_mink}, {}}; +static u3j_harm _137_qua_mole_a[] = {{".2", u3we_mole}, {}}; +static u3j_harm _137_qua_mule_a[] = {{".2", u3we_mule}, {}}; + + +static u3j_hood _137_qua_ho[] = { + { "mute", 0x2fbabe }, + { "show", 24406 }, + { "mure", 1374 }, + {}, +}; + + +/* layer three + */ +static u3j_harm _137_tri__cofl__drg_a[] = {{".2", u3wef_drg}, {}}; +static u3j_harm _137_tri__cofl__lug_a[] = {{".2", u3wef_lug}, {}}; +static u3j_core _137_tri__cofl_d[] = + { { "drg", 7, _137_tri__cofl__drg_a, 0, no_hashes }, + { "lug", 7, _137_tri__cofl__lug_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__rd_add_a[] = {{".2", u3wer_add}, {}}; +static u3j_harm _137_tri__rd_sub_a[] = {{".2", u3wer_sub}, {}}; +static u3j_harm _137_tri__rd_mul_a[] = {{".2", u3wer_mul}, {}}; +static u3j_harm _137_tri__rd_div_a[] = {{".2", u3wer_div}, {}}; +static u3j_harm _137_tri__rd_sqt_a[] = {{".2", u3wer_sqt}, {}}; +static u3j_harm _137_tri__rd_fma_a[] = {{".2", u3wer_fma}, {}}; +static u3j_harm _137_tri__rd_lth_a[] = {{".2", u3wer_lth}, {}}; +static u3j_harm _137_tri__rd_lte_a[] = {{".2", u3wer_lte}, {}}; +static u3j_harm _137_tri__rd_equ_a[] = {{".2", u3wer_equ}, {}}; +static u3j_harm _137_tri__rd_gte_a[] = {{".2", u3wer_gte}, {}}; +static u3j_harm _137_tri__rd_gth_a[] = {{".2", u3wer_gth}, {}}; +static u3j_core _137_tri__rd_d[] = + { { "add", 7, _137_tri__rd_add_a, 0, no_hashes }, + { "sub", 7, _137_tri__rd_sub_a, 0, no_hashes }, + { "mul", 7, _137_tri__rd_mul_a, 0, no_hashes }, + { "div", 7, _137_tri__rd_div_a, 0, no_hashes }, + { "sqt", 7, _137_tri__rd_sqt_a, 0, no_hashes }, + { "fma", 7, _137_tri__rd_fma_a, 0, no_hashes }, + { "lth", 7, _137_tri__rd_lth_a, 0, no_hashes }, + { "lte", 7, _137_tri__rd_lte_a, 0, no_hashes }, + { "equ", 7, _137_tri__rd_equ_a, 0, no_hashes }, + { "gte", 7, _137_tri__rd_gte_a, 0, no_hashes }, + { "gth", 7, _137_tri__rd_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__rs_add_a[] = {{".2", u3wet_add}, {}}; +static u3j_harm _137_tri__rs_sub_a[] = {{".2", u3wet_sub}, {}}; +static u3j_harm _137_tri__rs_mul_a[] = {{".2", u3wet_mul}, {}}; +static u3j_harm _137_tri__rs_div_a[] = {{".2", u3wet_div}, {}}; +static u3j_harm _137_tri__rs_sqt_a[] = {{".2", u3wet_sqt}, {}}; +static u3j_harm _137_tri__rs_fma_a[] = {{".2", u3wet_fma}, {}}; +static u3j_harm _137_tri__rs_lth_a[] = {{".2", u3wet_lth}, {}}; +static u3j_harm _137_tri__rs_lte_a[] = {{".2", u3wet_lte}, {}}; +static u3j_harm _137_tri__rs_equ_a[] = {{".2", u3wet_equ}, {}}; +static u3j_harm _137_tri__rs_gte_a[] = {{".2", u3wet_gte}, {}}; +static u3j_harm _137_tri__rs_gth_a[] = {{".2", u3wet_gth}, {}}; +static u3j_core _137_tri__rs_d[] = + { { "add", 7, _137_tri__rs_add_a, 0, no_hashes }, + { "sub", 7, _137_tri__rs_sub_a, 0, no_hashes }, + { "mul", 7, _137_tri__rs_mul_a, 0, no_hashes }, + { "div", 7, _137_tri__rs_div_a, 0, no_hashes }, + { "sqt", 7, _137_tri__rs_sqt_a, 0, no_hashes }, + { "fma", 7, _137_tri__rs_fma_a, 0, no_hashes }, + { "lth", 7, _137_tri__rs_lth_a, 0, no_hashes }, + { "lte", 7, _137_tri__rs_lte_a, 0, no_hashes }, + { "equ", 7, _137_tri__rs_equ_a, 0, no_hashes }, + { "gte", 7, _137_tri__rs_gte_a, 0, no_hashes }, + { "gth", 7, _137_tri__rs_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__rq_add_a[] = {{".2", u3weq_add}, {}}; +static u3j_harm _137_tri__rq_sub_a[] = {{".2", u3weq_sub}, {}}; +static u3j_harm _137_tri__rq_mul_a[] = {{".2", u3weq_mul}, {}}; +static u3j_harm _137_tri__rq_div_a[] = {{".2", u3weq_div}, {}}; +static u3j_harm _137_tri__rq_sqt_a[] = {{".2", u3weq_sqt}, {}}; +static u3j_harm _137_tri__rq_fma_a[] = {{".2", u3weq_fma}, {}}; +static u3j_harm _137_tri__rq_lth_a[] = {{".2", u3weq_lth}, {}}; +static u3j_harm _137_tri__rq_lte_a[] = {{".2", u3weq_lte}, {}}; +static u3j_harm _137_tri__rq_equ_a[] = {{".2", u3weq_equ}, {}}; +static u3j_harm _137_tri__rq_gte_a[] = {{".2", u3weq_gte}, {}}; +static u3j_harm _137_tri__rq_gth_a[] = {{".2", u3weq_gth}, {}}; +static u3j_core _137_tri__rq_d[] = + { { "add", 7, _137_tri__rq_add_a, 0, no_hashes }, + { "sub", 7, _137_tri__rq_sub_a, 0, no_hashes }, + { "mul", 7, _137_tri__rq_mul_a, 0, no_hashes }, + { "div", 7, _137_tri__rq_div_a, 0, no_hashes }, + { "sqt", 7, _137_tri__rq_sqt_a, 0, no_hashes }, + { "fma", 7, _137_tri__rq_fma_a, 0, no_hashes }, + { "lth", 7, _137_tri__rq_lth_a, 0, no_hashes }, + { "lte", 7, _137_tri__rq_lte_a, 0, no_hashes }, + { "equ", 7, _137_tri__rq_equ_a, 0, no_hashes }, + { "gte", 7, _137_tri__rq_gte_a, 0, no_hashes }, + { "gth", 7, _137_tri__rq_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__rh_add_a[] = {{".2", u3wes_add}, {}}; +static u3j_harm _137_tri__rh_sub_a[] = {{".2", u3wes_sub}, {}}; +static u3j_harm _137_tri__rh_mul_a[] = {{".2", u3wes_mul}, {}}; +static u3j_harm _137_tri__rh_div_a[] = {{".2", u3wes_div}, {}}; +static u3j_harm _137_tri__rh_sqt_a[] = {{".2", u3wes_sqt}, {}}; +static u3j_harm _137_tri__rh_fma_a[] = {{".2", u3wes_fma}, {}}; +static u3j_harm _137_tri__rh_lth_a[] = {{".2", u3wes_lth}, {}}; +static u3j_harm _137_tri__rh_lte_a[] = {{".2", u3wes_lte}, {}}; +static u3j_harm _137_tri__rh_equ_a[] = {{".2", u3wes_equ}, {}}; +static u3j_harm _137_tri__rh_gte_a[] = {{".2", u3wes_gte}, {}}; +static u3j_harm _137_tri__rh_gth_a[] = {{".2", u3wes_gth}, {}}; +static u3j_core _137_tri__rh_d[] = + { { "add", 7, _137_tri__rh_add_a, 0, no_hashes }, + { "sub", 7, _137_tri__rh_sub_a, 0, no_hashes }, + { "mul", 7, _137_tri__rh_mul_a, 0, no_hashes }, + { "div", 7, _137_tri__rh_div_a, 0, no_hashes }, + { "sqt", 7, _137_tri__rh_sqt_a, 0, no_hashes }, + { "fma", 7, _137_tri__rh_fma_a, 0, no_hashes }, + { "lth", 7, _137_tri__rh_lth_a, 0, no_hashes }, + { "lte", 7, _137_tri__rh_lte_a, 0, no_hashes }, + { "equ", 7, _137_tri__rh_equ_a, 0, no_hashes }, + { "gte", 7, _137_tri__rh_gte_a, 0, no_hashes }, + { "gth", 7, _137_tri__rh_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__og_raw_a[] = {{".2", u3weo_raw}, {}}; +static u3j_core _137_tri__og_d[] = + { { "raw", 7, _137_tri__og_raw_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__sha_sha1_a[] = {{".2", u3we_sha1}, {}}; +static u3j_core _137_tri__sha_d[] = + { { "sha1", 7, _137_tri__sha_sha1_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri_shax_a[] = {{".2", u3we_shax}, {}}; +static u3j_harm _137_tri_shay_a[] = {{".2", u3we_shay}, {}}; +static u3j_harm _137_tri_shas_a[] = {{".2", u3we_shas}, {}}; +static u3j_harm _137_tri_shal_a[] = {{".2", u3we_shal}, {}}; + +static u3j_harm _137_ob_fynd_a[] = {{".2", u3we_fynd_ob}, {}}; +static u3j_harm _137_ob_fein_a[] = {{".2", u3we_fein_ob}, {}}; +static u3j_core _137_ob_d[] = { + { "fein", 7, _137_ob_fein_a, 0, no_hashes }, + { "fynd", 7, _137_ob_fynd_a, 0, no_hashes }, + {} +}; +static u3j_hood _137_ob_ho[] = { + { "fein", 42 }, + { "fynd", 20 }, + {}, +}; + + +static u3j_hood _137_tri_ho[] = { + { "ob", 20 }, + { "yore", 5462 }, + { "year", 44975 }, + {}, +}; + + +/* layer two + */ +static u3j_harm _137_two_find_a[] = {{".2", u3wb_find, c3y}, {}}; +static u3j_harm _137_two_flop_a[] = {{".2", u3wb_flop, c3y}, {}}; +static u3j_harm _137_two_lent_a[] = {{".2", u3wb_lent, c3y}, {}}; +static u3j_harm _137_two_levy_a[] = {{".2", u3wb_levy, c3y}, {}}; +static u3j_harm _137_two_lien_a[] = {{".2", u3wb_lien, c3y}, {}}; +static u3j_harm _137_two_murn_a[] = {{".2", u3wb_murn, c3y}, {}}; +static u3j_harm _137_two_need_a[] = {{".2", u3wb_need, c3y}, {}}; +static u3j_harm _137_two_reap_a[] = {{".2", u3wb_reap, c3y}, {}}; +static u3j_harm _137_two_reel_a[] = {{".2", u3wb_reel, c3y}, {}}; +static u3j_harm _137_two_roll_a[] = {{".2", u3wb_roll, c3y}, {}}; +static u3j_harm _137_two_skid_a[] = {{".2", u3wb_skid, c3y}, {}}; +static u3j_harm _137_two_skim_a[] = {{".2", u3wb_skim, c3y}, {}}; +static u3j_harm _137_two_skip_a[] = {{".2", u3wb_skip, c3y}, {}}; +static u3j_harm _137_two_scag_a[] = {{".2", u3wb_scag, c3y}, {}}; +static u3j_harm _137_two_slag_a[] = {{".2", u3wb_slag, c3y}, {}}; +static u3j_harm _137_two_snag_a[] = {{".2", u3wb_snag, c3y}, {}}; +static u3j_harm _137_two_sort_a[] = {{".2", u3wb_sort, c3y}, {}}; +static u3j_harm _137_two_turn_a[] = {{".2", u3wb_turn, c3y}, {}}; +static u3j_harm _137_two_weld_a[] = {{".2", u3wb_weld, c3y}, {}}; +static u3j_harm _137_two_welp_a[] = {{".2", u3wb_welp, c3y}, {}}; +static u3j_harm _137_two_zing_a[] = {{".2", u3wb_zing, c3y}, {}}; + +static u3j_harm _137_two_bex_a[] = {{".2", u3wc_bex, c3y}, {}}; +static u3j_harm _137_two_can_a[] = {{".2", u3wc_can, c3y}, {}}; +static u3j_harm _137_two_cat_a[] = {{".2", u3wc_cat, c3y}, {}}; +static u3j_harm _137_two_con_a[] = {{".2", u3wc_con, c3y}, {}}; +static u3j_harm _137_two_cut_a[] = {{".2", u3wc_cut, c3y}, {}}; +static u3j_harm _137_two_dis_a[] = {{".2", u3wc_dis, c3y}, {}}; +static u3j_harm _137_two_dor_a[] = {{".2", u3wc_dor, c3y}, {}}; +static u3j_harm _137_two_end_a[] = {{".2", u3wc_end, c3y}, {}}; +static u3j_harm _137_two_gor_a[] = {{".2", u3wc_gor, c3y}, {}}; +static u3j_harm _137_two_lsh_a[] = {{".2", u3wc_lsh, c3y}, {}}; +static u3j_harm _137_two_met_a[] = {{".2", u3wc_met, c3y}, {}}; +static u3j_harm _137_two_mix_a[] = {{".2", u3wc_mix, c3y}, {}}; +static u3j_harm _137_two_mor_a[] = {{".2", u3wc_mor, c3y}, {}}; +static u3j_harm _137_two_mug_a[] = {{".2", u3wc_mug, c3y}, {}}; +static u3j_harm _137_two_muk_a[] = {{".2", u3wc_muk, c3y}, {}}; +static u3j_harm _137_two_pow_a[] = {{".2", u3wc_pow, c3y}, {}}; +static u3j_harm _137_two_rap_a[] = {{".2", u3wc_rap, c3y}, {}}; +static u3j_harm _137_two_rep_a[] = {{".2", u3wc_rep, c3y}, {}}; +static u3j_harm _137_two_rev_a[] = {{".2", u3wc_rev, c3y}, {}}; +static u3j_harm _137_two_rip_a[] = {{".2", u3wc_rip, c3y}, {}}; +static u3j_harm _137_two_rsh_a[] = {{".2", u3wc_rsh, c3y}, {}}; +static u3j_harm _137_two_swp_a[] = {{".2", u3wc_swp, c3y}, {}}; +static u3j_harm _137_two_sqt_a[] = {{".2", u3wc_sqt, c3y}, {}}; +static u3j_harm _137_two_xeb_a[] = {{".2", u3wc_xeb, c3y}, {}}; + +static u3j_harm _137_two__in_bif_a[] = {{".2", u3wdi_bif}, {}}; +static u3j_harm _137_two__in_del_a[] = {{".2", u3wdi_del}, {}}; +static u3j_harm _137_two__in_dif_a[] = {{".2", u3wdi_dif}, {}}; +static u3j_harm _137_two__in_gas_a[] = {{".2", u3wdi_gas}, {}}; +static u3j_harm _137_two__in_has_a[] = {{".2", u3wdi_has}, {}}; +static u3j_harm _137_two__in_int_a[] = {{".2", u3wdi_int}, {}}; +static u3j_harm _137_two__in_put_a[] = {{".2", u3wdi_put}, {}}; +static u3j_harm _137_two__in_rep_a[] = {{".2", u3wdi_rep}, {}}; +static u3j_harm _137_two__in_run_a[] = {{".2", u3wdi_run}, {}}; +static u3j_harm _137_two__in_tap_a[] = {{".2", u3wdi_tap}, {}}; +static u3j_harm _137_two__in_wyt_a[] = {{".2", u3wdi_wyt}, {}}; +static u3j_harm _137_two__in_uni_a[] = {{".2", u3wdi_uni}, {}}; + +static u3j_harm _137_two__by_all_a[] = {{".2", u3wdb_all, c3y}, {}}; +static u3j_harm _137_two__by_any_a[] = {{".2", u3wdb_any, c3y}, {}}; +static u3j_harm _137_two__by_apt_a[] = {{".2", u3wdb_apt, c3y}, {}}; + +static u3j_harm _137_two__by_del_a[] = {{".2", u3wdb_del, c3y}, {}}; +static u3j_harm _137_two__by_dif_a[] = {{".2", u3wdb_dif, c3y}, {}}; +static u3j_harm _137_two__by_gas_a[] = {{".2", u3wdb_gas, c3y}, {}}; +static u3j_harm _137_two__by_get_a[] = {{".2", u3wdb_get, c3y}, {}}; +static u3j_harm _137_two__by_has_a[] = {{".2", u3wdb_has, c3y}, {}}; +static u3j_harm _137_two__by_int_a[] = {{".2", u3wdb_int, c3y}, {}}; +static u3j_harm _137_two__by_jab_a[] = {{".2", u3wdb_jab, c3y}, {}}; +static u3j_harm _137_two__by_key_a[] = {{".2", u3wdb_key, c3y}, {}}; +static u3j_harm _137_two__by_put_a[] = {{".2", u3wdb_put, c3y}, {}}; +static u3j_harm _137_two__by_rep_a[] = {{".2", u3wdb_rep, c3y}, {}}; +static u3j_harm _137_two__by_run_a[] = {{".2", u3wdb_run, c3y}, {}}; +static u3j_harm _137_two__by_tap_a[] = {{".2", u3wdb_tap, c3y}, {}}; +static u3j_harm _137_two__by_uni_a[] = {{".2", u3wdb_uni, c3y}, {}}; +static u3j_harm _137_two__by_urn_a[] = {{".2", u3wdb_urn, c3y}, {}}; +static u3j_harm _137_two__by_wyt_a[] = {{".2", u3wdb_wyt, c3y}, {}}; + +static u3j_harm _137_two_cue_a[] = {{".2", u3we_cue}, {}}; +static u3j_harm _137_two_jam_a[] = {{".2", u3we_jam}, {}}; +static u3j_harm _137_two_mat_a[] = {{".2", u3we_mat}, {}}; +static u3j_harm _137_two_rub_a[] = {{".2", u3we_rub}, {}}; + + + +/* layer one + */ +static u3j_harm _137_one_add_a[] = {{".2", u3wa_add, c3y}, {}}; +static u3j_harm _137_one_dec_a[] = {{".2", u3wa_dec, c3y}, {}}; +static u3j_harm _137_one_div_a[] = {{".2", u3wa_div, c3y}, {}}; +static u3j_harm _137_one_dvr_a[] = {{".2", u3wc_dvr, c3y}, {}}; +static u3j_harm _137_one_gte_a[] = {{".2", u3wa_gte, c3y}, {}}; +static u3j_harm _137_one_gth_a[] = {{".2", u3wa_gth, c3y}, {}}; +static u3j_harm _137_one_lte_a[] = {{".2", u3wa_lte, c3y}, {}}; +static u3j_harm _137_one_lth_a[] = {{".2", u3wa_lth, c3y}, {}}; +static u3j_harm _137_one_max_a[] = {{".2", u3wa_max, c3y}, {}}; +static u3j_harm _137_one_min_a[] = {{".2", u3wa_min, c3y}, {}}; +static u3j_harm _137_one_mod_a[] = {{".2", u3wa_mod, c3y}, {}}; +static u3j_harm _137_one_mul_a[] = {{".2", u3wa_mul, c3y}, {}}; +static u3j_harm _137_one_sub_a[] = {{".2", u3wa_sub, c3y}, {}}; + +static u3j_harm _137_one_cap_a[] = {{".2", u3wc_cap, c3y}, {}}; +static u3j_harm _137_one_peg_a[] = {{".2", u3wc_peg, c3y}, {}}; +static u3j_harm _137_one_mas_a[] = {{".2", u3wc_mas, c3y}, {}}; + +static u3j_harm _137_lull_plot_fax_a[] = {{".2", u3wg_plot_fax, c3y}, {}}; +static u3j_harm _137_lull_plot_met_a[] = {{".2", u3wg_plot_met, c3y}, {}}; + +static u3j_core _137_lull_plot_d[] = + { { "fax", 7, _137_lull_plot_fax_a, 0, no_hashes }, + { "met", 7, _137_lull_plot_met_a, 0, no_hashes }, + {} + }; + +static u3j_core _137_lull_d[] = + { { "plot", 31, 0, _137_lull_plot_d, no_hashes }, + {} + }; + +static u3j_harm _137_hex_blake3_hash_a[] = {{".2", u3we_blake3_hash, c3y}, {}}; +static u3j_harm _137_hex_blake3_compress_a[] = {{".2", u3we_blake3_compress, c3y}, {}}; +static u3j_harm _137_hex_blake3_chunk_output_a[] = {{".2", u3we_blake3_chunk_output, c3y}, {}}; + +static u3j_core _137_hex_blake3_d[] = + { { "hash", 7, _137_hex_blake3_hash_a, 0, no_hashes }, + { "chunk-output", 7, _137_hex_blake3_chunk_output_a, 0, no_hashes }, + {} + }; + + +static u3j_core _137_hex_blake3_impl_d[] = + { { "compress", 7, _137_hex_blake3_compress_a, 0, no_hashes }, + { "blake3", 7, 0, _137_hex_blake3_d, no_hashes }, + {} + }; + +static u3j_harm _137_hex_blake2b_a[] = {{".2", u3we_blake2b, c3y}, {}}; + +static u3j_core _137_hex_blake_d[] = + { { "blake2b", 7, _137_hex_blake2b_a, 0, no_hashes }, + { "blake3-impl", 7, 0, _137_hex_blake3_impl_d, no_hashes }, + {} + }; + + +static u3j_harm _137_hex_chacha_crypt_a[] = {{".2", u3we_chacha_crypt, c3y}, {}}; +static u3j_harm _137_hex_chacha_xchacha_a[] = {{".2", u3we_chacha_xchacha, c3y}, {}}; +static u3j_core _137_hex_chacha_d[] = + { { "crypt", 7, _137_hex_chacha_crypt_a, 0, no_hashes }, + { "xchacha", 7, _137_hex_chacha_xchacha_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_json_de_a[] = {{".2", u3we_json_de}, {}}; +static u3j_harm _137_hex_json_en_a[] = {{".2", u3we_json_en}, {}}; +static u3j_core _137_hex_json_d[] = + { { "de", 15, _137_hex_json_de_a, 0, no_hashes }, + { "en", 15, _137_hex_json_en_a, 0, no_hashes }, + {} + }; + +/* /lib jets in non core +*/ +static u3j_harm _137_non__lagoon_add_a[] = {{".2", u3wi_la_add}, {}}; +static u3j_harm _137_non__lagoon_sub_a[] = {{".2", u3wi_la_sub}, {}}; +static u3j_harm _137_non__lagoon_mul_a[] = {{".2", u3wi_la_mul}, {}}; +static u3j_harm _137_non__lagoon_div_a[] = {{".2", u3wi_la_div}, {}}; +static u3j_harm _137_non__lagoon_mod_a[] = {{".2", u3wi_la_mod}, {}}; +static u3j_harm _137_non__lagoon_adds_a[] = {{".2", u3wi_la_adds}, {}}; +static u3j_harm _137_non__lagoon_subs_a[] = {{".2", u3wi_la_subs}, {}}; +static u3j_harm _137_non__lagoon_muls_a[] = {{".2", u3wi_la_muls}, {}}; +static u3j_harm _137_non__lagoon_divs_a[] = {{".2", u3wi_la_divs}, {}}; +static u3j_harm _137_non__lagoon_mods_a[] = {{".2", u3wi_la_mods}, {}}; +static u3j_harm _137_non__lagoon_dot_a[] = {{".2", u3wi_la_dot}, {}}; +static u3j_harm _137_non__lagoon_trans_a[] ={{".2", u3wi_la_transpose}, {}}; +static u3j_harm _137_non__lagoon_cumsum_a[]={{".2", u3wi_la_cumsum}, {}}; +static u3j_harm _137_non__lagoon_argmin_a[]={{".2", u3wi_la_argmin}, {}}; +static u3j_harm _137_non__lagoon_argmax_a[]={{".2", u3wi_la_argmax}, {}}; +static u3j_harm _137_non__lagoon_ravel_a[]={{".2", u3wi_la_ravel}, {}}; +static u3j_harm _137_non__lagoon_min_a[] = {{".2", u3wi_la_min}, {}}; +static u3j_harm _137_non__lagoon_max_a[] = {{".2", u3wi_la_max}, {}}; +static u3j_harm _137_non__lagoon_linspace_a[]={{".2", u3wi_la_linspace}, {}}; +static u3j_harm _137_non__lagoon_range_a[]= {{".2", u3wi_la_range}, {}}; +static u3j_harm _137_non__lagoon_abs_a[] = {{".2", u3wi_la_abs}, {}}; +static u3j_harm _137_non__lagoon_gth_a[] = {{".2", u3wi_la_gth}, {}}; +static u3j_harm _137_non__lagoon_gte_a[] = {{".2", u3wi_la_gte}, {}}; +static u3j_harm _137_non__lagoon_lth_a[] = {{".2", u3wi_la_lth}, {}}; +static u3j_harm _137_non__lagoon_lte_a[] = {{".2", u3wi_la_lte}, {}}; +static u3j_harm _137_non__lagoon_diag_a[] = {{".2", u3wi_la_diag}, {}}; +static u3j_harm _137_non__lagoon_trace_a[]= {{".2", u3wi_la_trace}, {}}; +static u3j_harm _137_non__lagoon_mmul_a[] = {{".2", u3wi_la_mmul}, {}}; + +static u3j_core _137_non__la_core_d[] = + { { "add-rays", 7, _137_non__lagoon_add_a, 0, no_hashes }, + { "sub-rays", 7, _137_non__lagoon_sub_a, 0, no_hashes }, + { "mul-rays", 7, _137_non__lagoon_mul_a, 0, no_hashes }, + { "div-rays", 7, _137_non__lagoon_div_a, 0, no_hashes }, + { "mod-rays", 7, _137_non__lagoon_mod_a, 0, no_hashes }, + { "add-scal", 7, _137_non__lagoon_adds_a, 0, no_hashes }, + { "sub-scal", 7, _137_non__lagoon_subs_a, 0, no_hashes }, + { "mul-scal", 7, _137_non__lagoon_muls_a, 0, no_hashes }, + { "div-scal", 7, _137_non__lagoon_divs_a, 0, no_hashes }, + { "mod-scal", 7, _137_non__lagoon_mods_a, 0, no_hashes }, + { "dot", 7, _137_non__lagoon_dot_a, 0, no_hashes }, + { "transpose",7, _137_non__lagoon_trans_a, 0, no_hashes }, + { "cumsum", 7, _137_non__lagoon_cumsum_a, 0, no_hashes }, + { "argmin", 7, _137_non__lagoon_argmin_a, 0, no_hashes }, + { "argmax", 7, _137_non__lagoon_argmax_a, 0, no_hashes }, + { "ravel", 7, _137_non__lagoon_ravel_a, 0, no_hashes }, + { "min", 7, _137_non__lagoon_min_a, 0, no_hashes }, + { "max", 7, _137_non__lagoon_max_a, 0, no_hashes }, + { "linspace", 7, _137_non__lagoon_linspace_a, 0, no_hashes }, + { "range", 7, _137_non__lagoon_range_a, 0, no_hashes }, + { "abs", 7, _137_non__lagoon_abs_a, 0, no_hashes }, + { "gth", 7, _137_non__lagoon_gth_a, 0, no_hashes }, + { "gte", 7, _137_non__lagoon_gte_a, 0, no_hashes }, + { "lth", 7, _137_non__lagoon_lth_a, 0, no_hashes }, + { "lte", 7, _137_non__lagoon_lte_a, 0, no_hashes }, + { "diag", 7, _137_non__lagoon_diag_a, 0, no_hashes }, + { "trace", 7, _137_non__lagoon_trace_a,0, no_hashes }, + { "mmul", 7, _137_non__lagoon_mmul_a, 0, no_hashes }, + {} + }; + +static u3j_core _137_non_d[] = + { { "lagoon", 7, 0, _137_non__la_core_d, no_hashes }, + {} + }; + + +static u3j_core _137_hex_d[] = + { { "non", 7, 0, _137_non_d, no_hashes }, + + { "lull", 3, 0, _137_lull_d, no_hashes }, + + { "lore", 63, _137_hex_lore_a, 0, no_hashes }, + + { "leer", 63, _137_hex_leer_a, 0, no_hashes }, + { "loss", 63, _137_hex_loss_a, 0, no_hashes }, + { "lune", 127, _137_hex_lune_a, 0, no_hashes }, + + { "crc", 31, 0, _137_hex__crc_d, no_hashes }, + + { "coed", 63, 0, _137_hex_coed_d, no_hashes }, + { "aes", 31, 0, _137_hex_aes_d, no_hashes }, + + { "hmac", 63, 0, _137_hex_hmac_d, no_hashes }, + { "argon", 31, 0, _137_hex_argon_d, no_hashes }, + { "blake", 31, 0, _137_hex_blake_d, no_hashes }, + { "chacha", 31, 0, _137_hex_chacha_d, no_hashes }, + { "kecc", 31, 0, _137_hex_kecc_d, no_hashes }, + { "ripemd", 31, 0, _137_hex_ripe_d, no_hashes }, + { "scr", 31, 0, _137_hex_scr_d, no_hashes }, + { "secp", 6, 0, _137_hex_secp_d, no_hashes }, + { "mimes", 31, 0, _137_hex_mimes_d, no_hashes }, + { "json", 31, 0, _137_hex_json_d, no_hashes }, + {} + }; + +static u3j_core _137_pen_d[] = + { { "hex", 7, 0, _137_hex_d, no_hashes }, + + { "cell", 7, _137_pen_cell_a, 0, no_hashes }, + { "comb", 7, _137_pen_comb_a, 0, no_hashes }, + { "cons", 7, _137_pen_cons_a, 0, no_hashes }, + { "core", 7, _137_pen_core_a, 0, no_hashes }, + { "face", 7, _137_pen_face_a, 0, no_hashes }, + { "fitz", 7, _137_pen_fitz_a, 0, no_hashes }, + { "fork", 7, _137_pen_fork_a, 0, no_hashes }, + { "look", 7, _137_pen_look_a, 0, no_hashes }, + { "loot", 7, _137_pen_loot_a, 0, no_hashes }, + { "ut", 15, 0, _137_pen__ut_d, no_hashes, _137_pen__ut_ho }, + {} + }; + +static u3j_core _137_qua_d[] = + { { "pen", 3, 0, _137_pen_d, no_hashes, _137_pen_ho }, + + { "po", 7, 0, _137_qua__po_d, no_hashes }, + + { "trip", 7, _137_qua_trip_a, 0, no_hashes }, + + { "bend", 7, 0, _137_qua__bend_d, no_hashes }, + { "cold", 7, 0, _137_qua__cold_d, no_hashes }, + { "comp", 7, 0, _137_qua__comp_d, no_hashes }, + { "cook", 7, 0, _137_qua__cook_d, no_hashes }, + { "easy", 7, 0, _137_qua__easy_d, no_hashes }, + { "glue", 7, 0, _137_qua__glue_d, no_hashes }, + { "here", 7, 0, _137_qua__here_d, no_hashes }, + { "just", 7, 0, _137_qua__just_d, no_hashes }, + { "mask", 7, 0, _137_qua__mask_d, no_hashes }, + { "shim", 7, 0, _137_qua__shim_d, no_hashes }, + { "stag", 7, 0, _137_qua__stag_d, no_hashes }, + { "stew", 7, 0, _137_qua__stew_d, no_hashes }, + { "stir", 7, 0, _137_qua__stir_d, no_hashes }, + + { "pfix", 7, _137_qua_pfix_a, 0, no_hashes }, + { "plug", 7, _137_qua_plug_a, 0, no_hashes }, + { "pose", 7, _137_qua_pose_a, 0, no_hashes }, + { "sfix", 7, _137_qua_sfix_a, 0, no_hashes }, + + { "mink", 7, _137_qua_mink_a, 0, no_hashes }, + { "mole", 7, _137_qua_mole_a, 0, no_hashes }, + { "mule", 7, _137_qua_mule_a, 0, no_hashes }, + + { "scot", 7, _137_qua_scot_a, 0, no_hashes }, + { "scow", 7, _137_qua_scow_a, 0, no_hashes }, + { "slaw", 7, _137_qua_slaw_a, 0, no_hashes }, + {} + }; + +static u3j_core _137_tri_d[] = + { { "qua", 3, 0, _137_qua_d, no_hashes, _137_qua_ho }, + + { "cofl", 7, 0, _137_tri__cofl_d, no_hashes }, + { "rd", 7, 0, _137_tri__rd_d, no_hashes }, + { "rs", 7, 0, _137_tri__rs_d, no_hashes }, + { "rq", 7, 0, _137_tri__rq_d, no_hashes }, + { "rh", 7, 0, _137_tri__rh_d, no_hashes }, + { "og", 7, 0, _137_tri__og_d, no_hashes }, + + { "sha", 7, 0, _137_tri__sha_d, no_hashes }, + { "shax", 7, _137_tri_shax_a, 0, no_hashes }, + { "shay", 7, _137_tri_shay_a, 0, no_hashes }, + { "shas", 7, _137_tri_shas_a, 0, no_hashes }, + { "shal", 7, _137_tri_shal_a, 0, no_hashes }, + + { "ob", 3, 0, _137_ob_d, no_hashes, _137_ob_ho }, + {} + }; + +static u3j_harm _137_two_clz_a[] = {{".2", u3wc_clz, c3n}, {}}; +static u3j_harm _137_two_ctz_a[] = {{".2", u3wc_ctz, c3n}, {}}; +static u3j_harm _137_two_ham_a[] = {{".2", u3wc_ham, c3n}, {}}; + +static u3j_harm _137_two__hew_fun_a[] = {{".2", u3wc_hew, c3n}, {}}; +static u3j_core _137_two__hew_d[] = + { { "fun", 15, _137_two__hew_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_two__by_bif_a[] = {{".2", u3wdb_bif, c3y}, {}}; + +static u3j_core _137_two__by_d[] = + { { "all", 7, _137_two__by_all_a, 0, no_hashes }, + { "any", 7, _137_two__by_any_a, 0, no_hashes }, + { "apt", 7, _137_two__by_apt_a, 0, no_hashes }, + { "bif", 7, _137_two__by_bif_a, 0, no_hashes }, + { "del", 7, _137_two__by_del_a, 0, no_hashes }, + { "dif", 7, _137_two__by_dif_a, 0, no_hashes }, + { "gas", 7, _137_two__by_gas_a, 0, no_hashes }, + { "get", 7, _137_two__by_get_a, 0, no_hashes }, + { "has", 7, _137_two__by_has_a, 0, no_hashes }, + { "int", 7, _137_two__by_int_a, 0, no_hashes }, + { "jab", 7, _137_two__by_jab_a, 0, no_hashes }, + { "key", 7, _137_two__by_key_a, 0, no_hashes }, + { "put", 7, _137_two__by_put_a, 0, no_hashes }, + { "rep", 7, _137_two__by_rep_a, 0, no_hashes }, + { "run", 7, _137_two__by_run_a, 0, no_hashes }, + { "tap", 7, _137_two__by_tap_a, 0, no_hashes }, + { "uni", 7, _137_two__by_uni_a, 0, no_hashes }, + { "urn", 7, _137_two__by_urn_a, 0, no_hashes }, + { "wyt", 3, _137_two__by_wyt_a, 0, no_hashes }, + {} + }; + + +static u3j_harm _137_two__in_apt_a[] = {{".2", u3wdi_apt}, {}}; + +static u3j_core _137_two__in_d[] = + { { "apt", 7, _137_two__in_apt_a, 0, no_hashes }, + { "bif", 7, _137_two__in_bif_a, 0, no_hashes }, + { "del", 7, _137_two__in_del_a, 0, no_hashes }, + { "dif", 7, _137_two__in_dif_a, 0, no_hashes }, + { "gas", 7, _137_two__in_gas_a, 0, no_hashes }, + { "has", 7, _137_two__in_has_a, 0, no_hashes }, + { "int", 7, _137_two__in_int_a, 0, no_hashes }, + { "put", 7, _137_two__in_put_a, 0, no_hashes }, + { "rep", 7, _137_two__in_rep_a, 0, no_hashes }, + { "run", 7, _137_two__in_run_a, 0, no_hashes }, + { "tap", 7, _137_two__in_tap_a, 0, no_hashes }, + { "uni", 7, _137_two__in_uni_a, 0, no_hashes }, + { "wyt", 3, _137_two__in_wyt_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_two_rig_a[] = {{".2", u3wc_rig, c3n}, {}}; + +static u3j_harm _137_two_mate_a[] = {{".2", u3wb_mate, c3y}, {}}; + +static u3j_core _137_two_d[] = + { { "tri", 3, 0, _137_tri_d, no_hashes, _137_tri_ho }, + + { "find", 7, _137_two_find_a, 0, no_hashes }, + { "flop", 7, _137_two_flop_a, 0, no_hashes }, + { "lent", 7, _137_two_lent_a, 0, no_hashes }, + { "levy", 7, _137_two_levy_a, 0, no_hashes }, + { "lien", 7, _137_two_lien_a, 0, no_hashes }, + { "murn", 7, _137_two_murn_a, 0, no_hashes }, + { "need", 7, _137_two_need_a, 0, no_hashes }, + { "mate", 7, _137_two_mate_a, 0, no_hashes }, + { "reap", 7, _137_two_reap_a, 0, no_hashes }, + { "reel", 7, _137_two_reel_a, 0, no_hashes }, + { "roll", 7, _137_two_roll_a, 0, no_hashes }, + { "skid", 7, _137_two_skid_a, 0, no_hashes }, + { "skim", 7, _137_two_skim_a, 0, no_hashes }, + { "skip", 7, _137_two_skip_a, 0, no_hashes }, + { "scag", 7, _137_two_scag_a, 0, no_hashes }, + { "slag", 7, _137_two_slag_a, 0, no_hashes }, + { "snag", 7, _137_two_snag_a, 0, no_hashes }, + { "sort", 7, _137_two_sort_a, 0, no_hashes }, + { "turn", 7, _137_two_turn_a, 0, no_hashes }, + { "weld", 7, _137_two_weld_a, 0, no_hashes }, + { "welp", 7, _137_two_welp_a, 0, no_hashes }, + { "zing", 7, _137_two_zing_a, 0, no_hashes }, + + { "bex", 7, _137_two_bex_a, 0, no_hashes }, + { "cat", 7, _137_two_cat_a, 0, no_hashes }, + { "can", 7, _137_two_can_a, 0, no_hashes }, + { "clz", 7, _137_two_clz_a, 0, no_hashes }, + { "con", 7, _137_two_con_a, 0, no_hashes }, + { "ctz", 7, _137_two_ctz_a, 0, no_hashes }, + { "cue", 7, _137_two_cue_a, 0, no_hashes }, + { "cut", 7, _137_two_cut_a, 0, no_hashes }, + { "dis", 7, _137_two_dis_a, 0, no_hashes }, + { "dor", 7, _137_two_dor_a, 0, no_hashes }, + { "end", 7, _137_two_end_a, 0, no_hashes }, + { "gor", 7, _137_two_gor_a, 0, no_hashes }, + { "ham", 7, _137_two_ham_a, 0, no_hashes }, + { "hew", 7, 0, _137_two__hew_d, no_hashes }, + { "jam", 7, _137_two_jam_a, 0, no_hashes }, + { "lsh", 7, _137_two_lsh_a, 0, no_hashes }, + { "mat", 7, _137_two_mat_a, 0, no_hashes }, + { "met", 7, _137_two_met_a, 0, no_hashes }, + { "mix", 7, _137_two_mix_a, 0, no_hashes }, + { "mor", 7, _137_two_mor_a, 0, no_hashes }, + { "mug", 7, _137_two_mug_a, 0, no_hashes }, + { "muk", 59, _137_two_muk_a, 0, no_hashes }, + { "rap", 7, _137_two_rap_a, 0, no_hashes }, + { "rep", 7, _137_two_rep_a, 0, no_hashes }, + { "rev", 7, _137_two_rev_a, 0, no_hashes }, + { "rig", 7, _137_two_rig_a, 0, no_hashes }, + { "rip", 7, _137_two_rip_a, 0, no_hashes }, + { "rsh", 7, _137_two_rsh_a, 0, no_hashes }, + { "swp", 7, _137_two_swp_a, 0, no_hashes }, + { "rub", 7, _137_two_rub_a, 0, no_hashes }, + { "pow", 7, _137_two_pow_a, 0, no_hashes }, + { "sqt", 7, _137_two_sqt_a, 0, no_hashes }, + { "xeb", 7, _137_two_xeb_a, 0, no_hashes }, + + { "by", 7, 0, _137_two__by_d, no_hashes }, + { "in", 7, 0, _137_two__in_d, no_hashes }, + {} + }; + +static u3j_core _137_one_d[] = + { { "two", 3, 0, _137_two_d, no_hashes }, + + { "add", 7, _137_one_add_a, 0, no_hashes }, + { "dec", 7, _137_one_dec_a, 0, no_hashes }, + { "div", 7, _137_one_div_a, 0, no_hashes }, + { "dvr", 7, _137_one_dvr_a, 0, no_hashes }, + { "gte", 7, _137_one_gte_a, 0, no_hashes }, + { "gth", 7, _137_one_gth_a, 0, no_hashes }, + { "lte", 7, _137_one_lte_a, 0, no_hashes }, + { "lth", 7, _137_one_lth_a, 0, no_hashes }, + { "max", 7, _137_one_max_a, 0, no_hashes }, + { "min", 7, _137_one_min_a, 0, no_hashes }, + { "mod", 7, _137_one_mod_a, 0, no_hashes }, + { "mul", 7, _137_one_mul_a, 0, no_hashes }, + { "sub", 7, _137_one_sub_a, 0, no_hashes }, + + { "cap", 7, _137_one_cap_a, 0, no_hashes }, + { "mas", 7, _137_one_mas_a, 0, no_hashes }, + { "peg", 7, _137_one_peg_a, 0, no_hashes }, + {} + }; + +u3j_core _k137_d[] = + { { "one", 3, 0, _137_one_d, no_hashes }, + {} + }; + diff --git a/pkg/noun/jets/c/clz.c b/pkg/noun/jets/c/clz.c new file mode 100644 index 0000000000..f8da45a3ce --- /dev/null +++ b/pkg/noun/jets/c/clz.c @@ -0,0 +1,75 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_atom +u3qc_clz(u3_atom boq, u3_atom sep, u3_atom a) +{ + if ( !_(u3a_is_cat(boq)) || (boq >= 32) ) { + return u3m_bail(c3__fail); + } + + if ( !_(u3a_is_cat(sep)) ) { + return u3m_bail(c3__fail); + } + + c3_g boq_g = boq; + c3_w sep_w = sep; + c3_w tot_w = sep_w << boq_g; + + if ( (tot_w >> boq_g) != sep_w ) { + return u3m_bail(c3__fail); + } + + c3_w met_w = u3r_met(0, a); + + if ( met_w <= tot_w ) { + tot_w -= met_w; + return u3i_word(tot_w); + } + else { + c3_w wid_w = tot_w >> 5; + c3_w bit_w = tot_w & 31; + c3_w wor_w; + + if ( bit_w ) { + wor_w = u3r_word(wid_w, a); + wor_w &= (1 << bit_w) - 1; + + if ( wor_w ) { + return bit_w - (32 - c3_lz_w(wor_w)); + } + } + + while ( wid_w-- ) { + wor_w = u3r_word(wid_w, a); + + if ( wor_w ) { + bit_w += c3_lz_w(wor_w); + break; + } + + bit_w += 32; + } + + return u3i_word(bit_w); + } +} + +u3_noun +u3wc_clz(u3_noun cor) +{ + u3_atom boq, sep, vat; + { + u3_noun sam = u3h(u3t(cor)); + u3_noun bit = u3h(sam); + + u3x_bite(bit, &boq, &sep); + vat = u3x_atom(u3t(sam)); + } + + return u3qc_clz(boq, sep, vat); +} diff --git a/pkg/noun/jets/c/ctz.c b/pkg/noun/jets/c/ctz.c new file mode 100644 index 0000000000..ff74e244c3 --- /dev/null +++ b/pkg/noun/jets/c/ctz.c @@ -0,0 +1,34 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_atom +u3qc_ctz(u3_atom a) +{ + c3_w wor_w, i_w = 0; + + if ( 0 == a ) { + return 0; + } + + do { + wor_w = u3r_word(i_w++, a); + } + while ( !wor_w ); + + { + c3_w bit_d = i_w - 1; + bit_d *= 32; + bit_d += c3_tz_w(wor_w); + return u3i_chub(bit_d); + } +} + +u3_noun +u3wc_ctz(u3_noun cor) +{ + return u3qc_ctz(u3x_atom(u3h(u3t(cor)))); +} diff --git a/pkg/noun/jets/c/ham.c b/pkg/noun/jets/c/ham.c new file mode 100644 index 0000000000..776cf0cd6e --- /dev/null +++ b/pkg/noun/jets/c/ham.c @@ -0,0 +1,27 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_atom +u3qc_ham(u3_atom a) +{ + c3_w len_w = u3r_met(5, a); + c3_d pop_d = 0; + c3_w wor_w; + + for ( c3_w i_w = 0; i_w < len_w; i_w++ ) { + wor_w = u3r_word(i_w, a); + pop_d += c3_pc_w(wor_w); + } + + return u3i_chub(pop_d); +} + +u3_noun +u3wc_ham(u3_noun cor) +{ + return u3qc_ham(u3x_atom(u3h(u3t(cor)))); +} diff --git a/pkg/noun/jets/c/hew.c b/pkg/noun/jets/c/hew.c new file mode 100644 index 0000000000..be6b7a76bd --- /dev/null +++ b/pkg/noun/jets/c/hew.c @@ -0,0 +1,87 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static c3_w +_hew_in(c3_g a_g, + c3_w pos_w, + u3_atom vat, + u3_noun sam, + u3_noun* out) +{ + u3_noun h, t, *l, *r; + + while ( c3y == u3r_cell(sam, &h, &t) ) { + *out = u3i_defcons(&l, &r); + pos_w = _hew_in(a_g, pos_w, vat, h, l); + sam = t; + out = r; + } + + if ( !_(u3a_is_cat(sam)) ) { + return u3m_bail(c3__fail); + } + + if ( !sam ) { + *out = 0; + return pos_w; + } + else { + c3_w wid_w = (c3_w)sam; + c3_w new_w = pos_w + wid_w; + u3i_slab sab_u; + + if ( new_w < pos_w ) { + return u3m_bail(c3__fail); + } + + u3i_slab_init(&sab_u, a_g, wid_w); + u3r_chop(a_g, pos_w, wid_w, 0, sab_u.buf_w, vat); + + *out = u3i_slab_mint(&sab_u); + return new_w; + } +} + +u3_noun +u3qc_hew(u3_atom boq, + u3_atom sep, + u3_atom vat, + u3_noun sam) +{ + if ( !_(u3a_is_cat(boq)) || (boq >= 32) ) { + return u3m_bail(c3__fail); + } + + if ( !_(u3a_is_cat(sep)) ) { + return u3m_bail(c3__fail); + } + + u3_noun pro; + c3_w pos_w = _hew_in((c3_g)boq, (c3_w)sep, vat, sam, &pro); + return u3nt(pro, boq, u3i_word(pos_w)); +} + +u3_noun +u3wc_hew(u3_noun cor) +{ + u3_atom boq, sep, vat; + u3_noun sam; + { + u3_noun pay = u3t(cor); + u3_noun con = u3t(pay); + u3_noun gat = u3t(con); // outer gate + u3_noun cam = u3h(u3t(gat)); // outer sample + u3_noun d = u3h(con); + + boq = u3x_atom(u3h(d)); + sep = u3x_atom(u3t(d)); + vat = u3x_atom(u3t(cam)); + sam = u3h(pay); + } + + return u3qc_hew(boq, sep, vat, sam); +} diff --git a/pkg/noun/jets/c/rig.c b/pkg/noun/jets/c/rig.c new file mode 100644 index 0000000000..7e5e7b958a --- /dev/null +++ b/pkg/noun/jets/c/rig.c @@ -0,0 +1,82 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +c3_d +u3qc_rig_s(c3_g foq_g, + c3_w sep_w, + c3_g toq_g) +{ + c3_d sep_d = sep_w; + + if ( foq_g >= toq_g ) { + return sep_d << (foq_g - toq_g); + } + else { + c3_g dif_g = toq_g - foq_g; + + sep_d += (1 << dif_g) - 1; + return sep_d >> dif_g; + } +} + +u3_noun +u3qc_rig(u3_atom foq, + u3_atom sep, + u3_atom toq) +{ + if ( c3y == u3r_sing(foq, toq) ) { + return u3k(sep); + } + + if ( (c3y == u3a_is_cat(foq)) && (foq < 32) + && (c3y == u3a_is_cat(toq)) && (toq < 32) + && (c3y == u3a_is_cat(sep)) ) + { + c3_d sep_d = u3qc_rig_s((c3_g)foq, (c3_w)sep, (c3_g)toq); + return u3i_chub(sep_d); + } + + if ( c3y == u3qa_gth(foq, toq) ) { + u3_atom d = u3qa_sub(foq, toq); + u3_atom e = u3qc_lsh(0, d, sep); + u3z(d); + return e; + } + else { + u3_atom d = u3qa_sub(toq, foq); + u3_atom e = u3qc_rsh(0, d, sep); + u3_atom f = u3qc_end(0, d, sep); + + if ( f ) { + e = u3i_vint(e); + u3z(f); + } + + u3z(d); + return e; + } +} + +u3_noun +u3wc_rig(u3_noun cor) +{ + u3_atom boq, sep, vat; + { + u3_noun sam = u3h(u3t(cor)); + u3_noun bit = u3h(sam); + + if ( c3y == u3a_is_atom(bit) ) { + return 0; + } + + boq = u3x_atom(u3h(bit)); + sep = u3x_atom(u3t(bit)); + vat = u3x_atom(u3t(sam)); + } + + return u3qc_rig(boq, sep, vat); +} diff --git a/pkg/noun/jets/e/blake.c b/pkg/noun/jets/e/blake.c index f21f229ceb..cac4c481ca 100644 --- a/pkg/noun/jets/e/blake.c +++ b/pkg/noun/jets/e/blake.c @@ -59,20 +59,21 @@ static u3_atom _cqe_blake3_hash(u3_atom wid, u3_atom dat, - u3_atom key, u3_atom out) + u3_atom key, u3_atom flags, u3_atom out) { c3_w wid_w, out_w; if ( !u3r_word_fit(&wid_w, wid) || !u3r_word_fit(&out_w, out) ) { return u3m_bail(c3__fail); } else { - c3_y key_y[32]; + c3_y key_y[32]; u3r_bytes(0, 32, key_y, key); + c3_y flags_y = u3r_byte(0, flags); c3_y *dat_y = u3r_bytes_alloc(0, wid_w, dat); u3i_slab sab_u; u3i_slab_bare(&sab_u, 3, out_w); c3_y* out_y = sab_u.buf_y; - urcrypt_blake3_hash(wid_w, dat_y, key_y, out, out_y); + urcrypt_blake3_hash(wid_w, dat_y, key_y, flags_y, out, out_y); u3a_free(dat_y); return u3i_slab_mint(&sab_u); } @@ -81,20 +82,20 @@ u3_noun u3we_blake3_hash(u3_noun cor) { - u3_noun out, msg, // arguments - wid, dat, // destructured msg - key; // context + u3_noun out, msg, // arguments + wid, dat, // destructured msg + sam, key, flags; // context if ( c3n == u3r_mean(cor, u3x_sam_2, &out, u3x_sam_3, &msg, - u3x_con_sam_2, &key, 0) || + u3x_con_sam, &sam, 0) || u3ud(out) || u3r_cell(msg, &wid, &dat) || u3ud(wid) || u3ud(dat) || - u3ud(key)) + u3r_cell(sam, &key, &flags) || u3ud(key) || u3ud(flags) ) { return u3m_bail(c3__exit); } else { - return u3l_punt("blake3_hash", _cqe_blake3_hash(wid, dat, key, out)); + return u3l_punt("blake3_hash", _cqe_blake3_hash(wid, dat, key, flags, out)); } } diff --git a/pkg/noun/jets/e/chacha.c b/pkg/noun/jets/e/chacha.c new file mode 100644 index 0000000000..e42f8e221c --- /dev/null +++ b/pkg/noun/jets/e/chacha.c @@ -0,0 +1,74 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqe_chacha_crypt(u3_atom rounds, u3_atom key, u3_atom nonce, u3_atom counter, u3_atom wid, u3_atom dat) + { + c3_w rounds_w, wid_w; + c3_d counter_d; + if ( !u3r_word_fit(&rounds_w, rounds) || !u3r_word_fit(&wid_w, wid) || c3n == u3r_safe_chub(counter, &counter_d) ) { + return u3m_bail(c3__fail); + } + else { + c3_y key_y[32], nonce_y[8]; + u3r_bytes(0, 32, key_y, key); + u3r_bytes(0, 8, nonce_y, nonce); + c3_y *dat_y = u3r_bytes_alloc(0, wid_w, dat); + urcrypt_chacha_crypt(rounds_w, key_y, nonce_y, counter_d, wid_w, dat_y); + u3_noun cry = u3i_bytes(wid_w, dat_y); + u3a_free(dat_y); + return u3i_cell(wid, cry); + } + } + + u3_noun + u3we_chacha_crypt(u3_noun cor) + { + u3_noun sam = u3x_at(u3x_sam, cor); + u3_noun rounds, key, nonce, counter, msg; + u3_noun wid, dat; + + if ( u3r_quil(sam, &rounds, &key, &nonce, &counter, &msg) || + u3ud(rounds) || u3ud(key) || u3ud(nonce) || u3ud(counter) || u3r_cell(msg, &wid, &dat) ) + { + return u3m_bail(c3__exit); + } else { + return u3l_punt("chacha_crypt", _cqe_chacha_crypt(rounds, key, nonce, counter, wid, dat)); + } + } + + + static u3_noun + _cqe_chacha_xchacha(u3_atom rounds, u3_atom key, u3_atom nonce) + { + c3_w rounds_w; + if ( !u3r_word_fit(&rounds_w, rounds) ) { + return u3m_bail(c3__fail); + } + c3_y key_y[32], nonce_y[64], xkey_y[32], xnonce_y[8]; + u3r_bytes(0, 32, key_y, key); + u3r_bytes(0, 24, nonce_y, nonce); + urcrypt_chacha_xchacha(rounds, key_y, nonce_y, xkey_y, xnonce_y); + return u3i_cell(u3i_bytes(32, xkey_y), u3i_bytes(8, xnonce_y)); + } + + u3_noun + u3we_chacha_xchacha(u3_noun cor) + { + u3_noun sam = u3x_at(u3x_sam, cor); + u3_noun rounds, key, nonce; + if ( c3n == u3r_trel(sam, &rounds, &key, &nonce) || + c3n == u3ud(rounds) || + c3n == u3ud(key) || + c3n == u3ud(nonce) ) + { + return u3m_bail(c3__exit); + } else { + return u3l_punt("chacha_xchacha", _cqe_chacha_xchacha(rounds, key, nonce)); + } + } diff --git a/pkg/noun/jets/e/crc32.c b/pkg/noun/jets/e/crc32.c new file mode 100644 index 0000000000..0daa032c7f --- /dev/null +++ b/pkg/noun/jets/e/crc32.c @@ -0,0 +1,59 @@ +/// @file + +#include +#include +#include "zlib.h" + +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qe_crc32(u3_noun input_octs) +{ + u3_atom head = u3h(input_octs); + u3_atom tail = u3t(input_octs); + c3_w tel_w = u3r_met(3, tail); + c3_w hed_w; + if ( c3n == u3r_safe_word(head, &hed_w) ) { + return u3m_bail(c3__fail); + } + c3_y* input; + + if (c3y == u3a_is_cat(tail)) { + input = (c3_y*)&tail; + } + else { + u3a_atom* vat_u = u3a_to_ptr(tail); + input = (c3_y*)vat_u->buf_w; + } + + if ( tel_w > hed_w ) { + return u3m_error("subtract-underflow"); + } + + c3_w led_w = hed_w - tel_w; + c3_w crc_w = 0; + + crc_w = crc32(crc_w, input, tel_w); + + while ( led_w > 0 ) { + c3_y byt_y = 0; + crc_w = crc32(crc_w, &byt_y, 1); + led_w--; + } + + return u3i_word(crc_w); +} + +u3_noun +u3we_crc32(u3_noun cor) +{ + u3_noun a = u3r_at(u3x_sam, cor); + + if ( (u3du(a) == c3y) && (u3ud(u3h(a)) == c3y) && (u3ud(u3t(a)) == c3y) ) { + return u3qe_crc32(a); + } else { + return u3m_bail(c3__exit); + } +} diff --git a/pkg/noun/jets/e/ed_sign.c b/pkg/noun/jets/e/ed_sign.c index 2728905d92..0cde84ec71 100644 --- a/pkg/noun/jets/e/ed_sign.c +++ b/pkg/noun/jets/e/ed_sign.c @@ -5,6 +5,42 @@ #include "noun.h" #include "urcrypt.h" +#include +#include + + static u3_atom + _cqee_sign_octs(u3_noun len, u3_noun dat, u3_noun key) + { + c3_y key_y[32]; + c3_w len_w; + if ( 0 != u3r_bytes_fit(32, key_y, key) ) { + // hoon calls suck, which calls puck, which crashes + return u3m_bail(c3__exit); + } + else if ( !u3r_word_fit(&len_w, len) ) { + return u3m_bail(c3__fail); + } + else { + c3_y sig_y[64]; + c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat); + urcrypt_ed_sign(dat_y, len_w, key_y, sig_y); + u3a_free(dat_y); + return u3i_bytes(64, sig_y); + } + } + + u3_noun + u3wee_sign_octs(u3_noun cor) + { + u3_noun msg, key; + u3_noun len, dat; + if ( c3n == u3r_mean(cor, u3x_sam_2, &msg, u3x_sam_3, &key, 0) || + c3n == u3r_cell(msg, &len, &dat) ) { + return u3m_bail(c3__fail); + } else { + return _cqee_sign_octs(len, dat, key); + } + } static u3_atom _cqee_sign(u3_noun a, diff --git a/pkg/noun/jets/e/ed_veri.c b/pkg/noun/jets/e/ed_veri.c index 742469f075..82649fb939 100644 --- a/pkg/noun/jets/e/ed_veri.c +++ b/pkg/noun/jets/e/ed_veri.c @@ -6,6 +6,44 @@ #include "noun.h" #include "urcrypt.h" + static u3_atom + _cqee_veri_octs(u3_noun sig, + u3_noun len, + u3_noun dat, + u3_noun pub) + { + c3_y sig_y[64], pub_y[32]; + c3_w len_w; + if ( (0 != u3r_bytes_fit(64, sig_y, sig)) || + (0 != u3r_bytes_fit(32, pub_y, pub)) || + !u3r_word_fit(&len_w, len) ) { + // hoon checks sizes, but weirdly and without crashes + return u3_none; + } + else { + c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat); + c3_t val_t = urcrypt_ed_veri(dat_y, len_w, pub_y, sig_y); + u3a_free(dat_y); + + return val_t ? c3y : c3n; + } + } + + u3_noun + u3wee_veri_octs(u3_noun cor) + { + u3_noun sig, msg, pub; + u3_noun len, dat; + if ( c3n == u3r_mean(cor, + u3x_sam_2, &sig, u3x_sam_6, &msg, + u3x_sam_7, &pub, 0) || + c3n == u3r_cell(msg, &len, &dat) ){ + return u3m_bail(c3__fail); + } else { + return u3l_punt("veri-octs", _cqee_veri_octs(sig, len, dat, pub)); + } + } + static u3_atom _cqee_veri(u3_noun s, u3_noun m, diff --git a/pkg/noun/jets/g/plot.c b/pkg/noun/jets/g/plot.c new file mode 100644 index 0000000000..18c8ab03b7 --- /dev/null +++ b/pkg/noun/jets/g/plot.c @@ -0,0 +1,364 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +// XX optimize +// +static c3_w +_met_plat_m(c3_g a_g, c3_w fum_w, c3_w met_w, u3_atom vat) +{ + c3_w len_w, wor_w; + + { + u3i_slab sab_u; + u3i_slab_init(&sab_u, a_g, met_w); + u3r_chop(a_g, fum_w, met_w, 0, sab_u.buf_w, vat); + + len_w = sab_u.len_w; + + while ( len_w && !sab_u.buf_w[len_w - 1] ) { + len_w--; + } + + wor_w = !len_w ? 0 : sab_u.buf_w[len_w - 1]; + + u3i_slab_free(&sab_u); + } + + + if ( !len_w ) { + return 0; + } + + { + c3_w gal_w = len_w - 1; + c3_w daz_w = wor_w; + c3_y a_y = a_g; + + // inlined from u3r_met + if (a_y < 5) { + c3_y max_y = (1 << a_y) - 1; + c3_y gow_y = 5 - a_y; + + if (gal_w > ((UINT32_MAX - (32 + max_y)) >> gow_y)) { + return u3m_bail(c3__fail); + } + + return (gal_w << gow_y) + + ((c3_bits_word(daz_w) + max_y) + >> a_y); + } + + { + c3_y gow_y = (a_y - 5); + return ((gal_w + 1) + ((1 << gow_y) - 1)) >> gow_y; + } + } +} + +static c3_w +_met_list(c3_g a_g, + c3_w sep_w, + u3_noun b_p); + +static c3_w +_met_pair(c3_g* las_g, + c3_w sep_w, + u3_noun a_p, + u3_noun b_p, + c3_g* new_g) +{ + c3_g res_g, a_g; + + while ( c3y == u3a_is_cell(a_p) ) { + sep_w = _met_pair(las_g, sep_w, u3h(a_p), u3t(a_p), &res_g); + las_g = &res_g; + a_p = u3h(b_p); + b_p = u3t(b_p); + } + + if ( !_(u3a_is_cat(a_p)) || (a_p >= 32) ) { + return u3m_bail(c3__fail); + } + + a_g = (c3_g)a_p; + + if ( las_g && (a_g != *las_g) ) { + sep_w = u3qc_rig_s(*las_g, sep_w, a_g); // XX overflow + } + + *new_g = a_g; + return _met_list(a_g, sep_w, b_p); +} + +static c3_w +_met_list(c3_g a_g, + c3_w sep_w, + u3_noun b_p) +{ + if ( u3_nul != b_p ) { + c3_w met_w; + u3_noun i, t = b_p; + + do { + u3x_cell(t, &i, &t); + + // ?@ i.b.p + if ( c3y == u3a_is_atom(i) ) { + met_w = u3r_met(a_g, i); + sep_w += met_w; // XX overflow + } + else { + u3_noun i_i, t_i; + u3x_cell(i, &i_i, &t_i); + + // ?=(@ -.i.b.p) + if ( c3y == u3a_is_atom(i_i) ) { + if ( !_(u3a_is_cat(i_i)) ) { + return u3m_bail(c3__fail); + } + + met_w = (c3_w)i_i; + sep_w += met_w; // XX overflow + } + else { + u3_noun l, r; + c3_o cel_o = u3r_cell(i_i, &l, &r); + + // ?=([%c ~] -.i.b.p) + if ( (c3y == cel_o) && ('c' == l) && (u3_nul == r) ) { + u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i))); + u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i))); + u3_atom q_t_i = u3x_atom(u3t(t_i)); + + if ( !_(u3a_is_cat(p_p_t_i)) + || !_(u3a_is_cat(q_p_t_i)) + || !_(u3a_is_cat(q_t_i)) ) + { + return u3m_bail(c3__fail); + } + + met_w = (c3_w)q_p_t_i; + sep_w += met_w; // XX overflow + } + // ?=([%m ~] -.i.b.p) + else if ( (c3y == cel_o) && ('m' == l) && (u3_nul == r) ) { + u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i))); + u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i))); + u3_atom q_t_i = u3x_atom(u3t(t_i)); + + if ( !_(u3a_is_cat(p_p_t_i)) + || !_(u3a_is_cat(q_p_t_i)) + || !_(u3a_is_cat(q_t_i)) ) + { + return u3m_bail(c3__fail); + } + + met_w = _met_plat_m(a_g, (c3_w)p_p_t_i, (c3_w)q_p_t_i, q_t_i); + sep_w += met_w; // XX overflow + } + // ?=([%s ~] -.i.b.p) (assumed) + else { + c3_g new_g; + u3x_cell(t_i, &l, &r); + + sep_w = _met_pair(&a_g, sep_w, l, r, &new_g); + + if ( new_g != a_g ) { + sep_w = u3qc_rig_s(new_g, sep_w, a_g); // XX overflow + } + } + } + } + } + while ( u3_nul != t ); + } + + return sep_w; +} + +static c3_w +_fax_list(u3i_slab* sab_u, + c3_g a_g, + c3_w sep_w, + u3_noun b_p); + +static c3_w +_fax_pair(u3i_slab* sab_u, + c3_g* las_g, + c3_w sep_w, + u3_noun a_p, + u3_noun b_p, + c3_g* new_g) +{ + c3_g res_g, a_g; + + while ( c3y == u3a_is_cell(a_p) ) { + sep_w = _fax_pair(sab_u, las_g, sep_w, u3h(a_p), u3t(a_p), &res_g); + las_g = &res_g; + a_p = u3h(b_p); + b_p = u3t(b_p); + } + + if ( !_(u3a_is_cat(a_p)) || (a_p >= 32) ) { + return u3m_bail(c3__fail); + } + + a_g = (c3_g)a_p; + + if ( las_g && (a_g != *las_g) ) { + sep_w = u3qc_rig_s(*las_g, sep_w, a_g); // XX overflow + } + + *new_g = a_g; + return _fax_list(sab_u, a_g, sep_w, b_p); +} + +static c3_w +_fax_list(u3i_slab* sab_u, + c3_g a_g, + c3_w sep_w, + u3_noun b_p) +{ + if ( u3_nul != b_p ) { + c3_w met_w; + u3_noun i, t = b_p; + + do { + u3x_cell(t, &i, &t); + + // ?@ i.b.p + if ( c3y == u3a_is_atom(i) ) { + met_w = u3r_met(a_g, i); + + u3r_chop(a_g, 0, met_w, sep_w, sab_u->buf_w, i); + + sep_w += met_w; // XX overflow + } + else { + u3_noun i_i, t_i; + u3x_cell(i, &i_i, &t_i); + + // ?=(@ -.i.b.p) + if ( c3y == u3a_is_atom(i_i) ) { + if ( !_(u3a_is_cat(i_i)) ) { + return u3m_bail(c3__fail); + } + + met_w = (c3_w)i_i; + + u3r_chop(a_g, 0, met_w, sep_w, sab_u->buf_w, u3x_atom(t_i)); + + sep_w += met_w; // XX overflow + } + else { + u3_noun l, r; + c3_o cel_o = u3r_cell(i_i, &l, &r); + + // ?=([%c ~] -.i.b.p) + if ( (c3y == cel_o) && ('c' == l) && (u3_nul == r) ) { + u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i))); + u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i))); + u3_atom q_t_i = u3x_atom(u3t(t_i)); + + if ( !_(u3a_is_cat(p_p_t_i)) + || !_(u3a_is_cat(q_p_t_i)) + || !_(u3a_is_cat(q_t_i)) ) + { + return u3m_bail(c3__fail); + } + + met_w = (c3_w)q_p_t_i; + + u3r_chop(a_g, (c3_w)p_p_t_i, met_w, sep_w, sab_u->buf_w, q_t_i); + + sep_w += met_w; // XX overflow + } + // ?=([%m ~] -.i.b.p) + else if ( (c3y == cel_o) && ('m' == l) && (u3_nul == r) ) { + u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i))); + u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i))); + u3_atom q_t_i = u3x_atom(u3t(t_i)); + + if ( !_(u3a_is_cat(p_p_t_i)) + || !_(u3a_is_cat(q_p_t_i)) + || !_(u3a_is_cat(q_t_i)) ) + { + return u3m_bail(c3__fail); + } + + met_w = _met_plat_m(a_g, (c3_w)p_p_t_i, (c3_w)q_p_t_i, q_t_i); + + u3r_chop(a_g, (c3_w)p_p_t_i, met_w, sep_w, sab_u->buf_w, q_t_i); + + sep_w += met_w; // XX overflow + } + // ?=([%s ~] -.i.b.p) (assumed) + else { + c3_g new_g; + u3x_cell(t_i, &l, &r); + + sep_w = _fax_pair(sab_u, &a_g, sep_w, l, r, &new_g); + + if ( new_g != a_g ) { + sep_w = u3qc_rig_s(new_g, sep_w, a_g); // XX overflow + } + } + } + } + } + while ( u3_nul != t ); + } + + return sep_w; +} + +u3_noun +u3qg_plot_met(u3_noun a_p, u3_noun b_p) +{ + c3_g out_g; + c3_w sep_w = _met_pair(NULL, 0, a_p, b_p, &out_g); + + return u3nc(out_g, u3i_word(sep_w)); +} + +u3_noun +u3wg_plot_met(u3_noun cor) +{ + u3_noun a_p, b_p; + { + u3_noun sam = u3h(u3t(cor)); + a_p = u3h(sam); + b_p = u3t(sam); + } + return u3qg_plot_met(a_p, b_p); +} + +u3_noun +u3qg_plot_fax(u3_noun a_p, u3_noun b_p) +{ + c3_g out_g; + c3_w sep_w = _met_pair(NULL, 0, a_p, b_p, &out_g); + u3i_slab sab_u; + + u3i_slab_init(&sab_u, out_g, sep_w); + + _fax_pair(&sab_u, NULL, 0, a_p, b_p, &out_g); + + return u3nt(u3i_slab_mint(&sab_u), out_g, u3i_word(sep_w)); +} + +u3_noun +u3wg_plot_fax(u3_noun cor) +{ + u3_noun a_p, b_p; + { + u3_noun sam = u3h(u3t(cor)); + a_p = u3h(sam); + b_p = u3t(sam); + } + return u3qg_plot_fax(a_p, b_p); +} diff --git a/pkg/noun/jets/i/lagoon.c b/pkg/noun/jets/i/lagoon.c new file mode 100644 index 0000000000..db7088b96e --- /dev/null +++ b/pkg/noun/jets/i/lagoon.c @@ -0,0 +1,3315 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "c3/motes.h" + +#include "noun.h" +#include "softfloat.h" +#include "softblas.h" + +#include // for pow() +#include + +#define f16_ceil(a) f16_roundToInt( a, softfloat_round_max, false ) +#define f32_ceil(a) f32_roundToInt( a, softfloat_round_max, false ) +#define f64_ceil(a) f64_roundToInt( a, softfloat_round_max, false ) +#define f128M_ceil(a, b) f128M_roundToInt( a, softfloat_round_max, false, b ) + + union half { + float16_t h; + c3_w c; + }; + + union sing { + float32_t s; + c3_w c; + }; + + union doub { + float64_t d; + c3_d c; + }; + + union quad { + float128_t q; + c3_d c[2]; + }; + + // $?(%n %u %d %z %a) + static inline void + _set_rounding(c3_w a) + { + // We could use SoftBLAS set_rounding() to set the SoftFloat + // mode as well, but it's more explicit to do it here since + // we may use SoftFloat in any given Lagoon jet and we want + // you, dear developer, to see it set here. + switch ( a ) + { + default: + u3m_bail(c3__fail); + break; + // %n - near + case c3__n: + softfloat_roundingMode = softfloat_round_near_even; + softblas_roundingMode = 'n'; + break; + // %z - zero + case c3__z: + softfloat_roundingMode = softfloat_round_minMag; + softblas_roundingMode = 'z'; + break; + // %u - up + case c3__u: + softfloat_roundingMode = softfloat_round_max; + softblas_roundingMode = 'u'; + break; + // %d - down + case c3__d: + softfloat_roundingMode = softfloat_round_min; + softblas_roundingMode = 'd'; + break; + // %a - away + case c3__a: + softfloat_roundingMode = softfloat_round_near_maxMag; + softblas_roundingMode = 'a'; + break; + } + } + +/* length of shape = x * y * z * w * ... +*/ + static inline c3_d _get_length(u3_noun shape) + { + c3_d len = 1; + while (u3_nul != shape) { + len = len * u3x_atom(u3h(shape)); + shape = u3t(shape); + } + return len; + } + +/* get dims from shape as array [x y z w ...] +*/ + static inline c3_d* _get_dims(u3_noun shape) + { + u3_atom len = u3qb_lent(shape); + c3_d len_d = u3r_chub(0, len); + c3_d* dims = (c3_d*)u3a_malloc(len_d*sizeof(c3_d)); + for (c3_d i = 0; i < len_d; i++) { + dims[i] = u3r_chub(0, u3x_atom(u3h(shape))); + shape = u3t(shape); + } + u3z(len); + return dims; + } + +/* check consistency of array shape and bloq size + |= =ray + ^- ? + .= (roll shape.meta.ray ^mul) + (dec (met bloq.meta.ray data.ray)) +*/ + static inline c3_o _check(u3_noun ray) + { + // Calculate expected size. + u3_atom shp = u3h(u3h(ray)); // (reported) shape of ray, +4 + u3_atom blq = u3h(u3t(u3h(ray))); // block size of ray, +10 + u3_atom sin = _get_length(shp); // calculated length of ray + + // Calculate actual size. + u3_atom len = u3r_met(blq, u3t(ray)); // length of ray + u3_atom dex = u3qa_dec(len); // decrement length b/c of pinned 1 + + return __(sin == dex); + } + +/* add - axpy = 1*x+y +*/ + u3_noun + u3qi_la_add_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq + ) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + haxpy(len_x, (float16_t){SB_REAL16_ONE}, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1); + break; + + case 5: + saxpy(len_x, (float32_t){SB_REAL32_ONE}, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1); + break; + + case 6: + daxpy(len_x, (float64_t){SB_REAL64_ONE}, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1); + break; + + case 7: + qaxpy(len_x, (float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1); + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* sub - axpy = -1*y+x +*/ + u3_noun + u3qi_la_sub_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq + ) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + haxpy(len_x, (float16_t){SB_REAL16_NEGONE}, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1); + break; + + case 5: + saxpy(len_x, (float32_t){SB_REAL32_NEGONE}, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1); + break; + + case 6: + daxpy(len_x, (float64_t){SB_REAL64_NEGONE}, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1); + break; + + case 7: + qaxpy(len_x, (float128_t){SB_REAL128L_NEGONE,SB_REAL128U_NEGONE}, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1); + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + + +/* mul - x.*y + elementwise multiplication +*/ + u3_noun + u3qi_la_mul_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + ((float16_t*)y_bytes)[i] = f16_mul(((float16_t*)x_bytes)[i], ((float16_t*)y_bytes)[i]); + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + ((float32_t*)y_bytes)[i] = f32_mul(((float32_t*)x_bytes)[i], ((float32_t*)y_bytes)[i]); + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + ((float64_t*)y_bytes)[i] = f64_mul(((float64_t*)x_bytes)[i], ((float64_t*)y_bytes)[i]); + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + f128M_mul(&(((float128_t*)y_bytes)[i]), &(((float128_t*)x_bytes)[i]), &(((float128_t*)y_bytes)[i])); + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* div - x/y + elementwise division +*/ + u3_noun + u3qi_la_div_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + ((float16_t*)y_bytes)[i] = f16_div(((float16_t*)x_bytes)[i], ((float16_t*)y_bytes)[i]); + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + ((float32_t*)y_bytes)[i] = f32_div(((float32_t*)x_bytes)[i], ((float32_t*)y_bytes)[i]); + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + ((float64_t*)y_bytes)[i] = f64_div(((float64_t*)x_bytes)[i], ((float64_t*)y_bytes)[i]); + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + f128M_div(&(((float128_t*)y_bytes)[i]), &(((float128_t*)x_bytes)[i]), &(((float128_t*)y_bytes)[i])); + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* mod - x % y = x - r*floor(x/r) + remainder after division +*/ + u3_noun + u3qi_la_mod_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + float16_t y_val16 = ((float16_t*)y_bytes)[i]; + // Perform division x/n + float16_t div_result16 = f16_div(x_val16, y_val16); + // Compute floor of the division result + c3_ds floor_result16 = f16_to_i64(div_result16, softfloat_round_minMag, false); + float16_t floor_float16 = i64_to_f16(floor_result16); + // Multiply n by floor(x/n) + float16_t mult_result16 = f16_mul(y_val16, floor_float16); + // Compute remainder: x - n * floor(x/n) + ((float16_t*)y_bytes)[i] = f16_sub(x_val16, mult_result16); + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + float32_t y_val32 = ((float32_t*)y_bytes)[i]; + // Perform division x/n + float32_t div_result32 = f32_div(x_val32, y_val32); + // Compute floor of the division result + c3_ds floor_result32 = f32_to_i64(div_result32, softfloat_round_minMag, false); + float32_t floor_float32 = i64_to_f32(floor_result32); + // Multiply n by floor(x/n) + float32_t mult_result32 = f32_mul(y_val32, floor_float32); + // Compute remainder: x - n * floor(x/n) + ((float32_t*)y_bytes)[i] = f32_sub(x_val32, mult_result32); + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + float64_t y_val64 = ((float64_t*)y_bytes)[i]; + // Perform division x/n + float64_t div_result64 = f64_div(x_val64, y_val64); + // Compute floor of the division result + c3_ds floor_result64 = f64_to_i64(div_result64, softfloat_round_minMag, false); + float64_t floor_float64 = i64_to_f64(floor_result64); + // Multiply n by floor(x/n) + float64_t mult_result64 = f64_mul(y_val64, floor_float64); + // Compute remainder: x - n * floor(x/n) + ((float64_t*)y_bytes)[i] = f64_sub(x_val64, mult_result64); + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + float128_t y_val128 = ((float128_t*)y_bytes)[i]; + // Perform division x/n + float128_t div_result128; + f128M_div((float128_t*)&x_val128, (float128_t*)&y_val128, (float128_t*)&div_result128); + // Compute floor of the division result + c3_ds floor_result128 = f128M_to_i64(&div_result128, softfloat_round_minMag, false); + float128_t floor_float128; + i64_to_f128M(floor_result128, &floor_float128); + // Multiply n by floor(x/n) + float128_t mult_result128; + f128M_mul(((float128_t*)&y_val128), ((float128_t*)&floor_float128), ((float128_t*)&mult_result128)); + // Compute remainder: x - n * floor(x/n) + f128M_sub(((float128_t*)&x_val128), ((float128_t*)&mult_result128), &(((float128_t*)y_bytes)[i])); + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* cumsum - x[0] + x[1] + ... x[n] +*/ + u3_noun + u3qi_la_cumsum_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // y_bytes is the data array (w/ leading 0x1, skipped by for range) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + + u3_noun r_data; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t sum16[2]; + sum16[0] = (float16_t){SB_REAL16_ZERO}; + for (c3_d i = len_x; i > 0; i--) { + sum16[0] = f16_add(sum16[0], ((float16_t*)x_bytes)[i-1]); + } + sum16[1].v = 0x1; + r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)sum16); + break;} + + case 5: { + float32_t sum32[2]; + sum32[0] = (float32_t){SB_REAL32_ZERO}; + for (c3_d i = len_x; i > 0; i--) { + sum32[0] = f32_add(sum32[0], ((float32_t*)x_bytes)[i-1]); + } + sum32[1].v = 0x1; + r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)sum32); + break;} + + case 6: { + float64_t sum64[2]; + sum64[0] = (float64_t){SB_REAL64_ZERO}; + for (c3_d i = len_x; i > 0; i--) { + sum64[0] = f64_add(sum64[0], ((float64_t*)x_bytes)[i-1]); + } + sum64[1].v = 0x1; + r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)sum64); + break;} + + case 7: { + float128_t sum128[2]; + sum128[0] = (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO}; + for (c3_d i = len_x; i > 0; i--) { + f128M_add(&(sum128[0]), &(((float128_t*)x_bytes)[i-1]), &(sum128[0])); + } + sum128[1] = (float128_t){0x1, 0x0}; + r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)sum128); + break;} + } + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* argmin - argmin(x) +*/ + u3_noun + u3qi_la_argmin_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1, which doesn't matter here) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + c3_w min_idx = 0; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t min_val16 = ((float16_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f16_lt(((float16_t*)x_bytes)[i], min_val16)) { + min_val16 = ((float16_t*)x_bytes)[i]; + min_idx = (len_x - i - 1); + } + } + break;} + + case 5: { + float32_t min_val32 = ((float32_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f32_lt(((float32_t*)x_bytes)[i], min_val32)) { + min_val32 = ((float32_t*)x_bytes)[i]; + min_idx = (len_x - i - 1); + } + } + break;} + + case 6: { + float64_t min_val64 = ((float64_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f64_lt(((float64_t*)x_bytes)[i], min_val64)) { + min_val64 = ((float64_t*)x_bytes)[i]; + min_idx = (len_x - i - 1); + } + } + break;} + + case 7: { + float128_t min_val128 = ((float128_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f128M_lt(&(((float128_t*)x_bytes)[i]), &min_val128)) { + min_val128 = *f128M_min(&min_val128, &((float128_t*)x_bytes)[i]); + min_idx = (len_x - i - 1); + } + } + break;} + } + + u3_noun r_data = u3i_chub(min_idx); + + return r_data; + } + +/* argmax - argmax(x) +*/ + u3_noun + u3qi_la_argmax_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1, which doesn't matter here) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + c3_w max_idx = 0; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t max_val16 = ((float16_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f16_gt(((float16_t*)x_bytes)[i], max_val16)) { + max_val16 = ((float16_t*)x_bytes)[i]; + max_idx = (len_x - i - 1); + } + } + break;} + + case 5: { + float32_t max_val32 = ((float32_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f32_gt(((float32_t*)x_bytes)[i], max_val32)) { + max_val32 = ((float32_t*)x_bytes)[i]; + max_idx = (len_x - i - 1); + } + } + break;} + + case 6: { + float64_t max_val64 = ((float64_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f64_gt(((float64_t*)x_bytes)[i], max_val64)) { + max_val64 = ((float64_t*)x_bytes)[i]; + max_idx = (len_x - i - 1); + } + } + break;} + + case 7: { + float128_t max_val128 = ((float128_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f128M_gt(&(((float128_t*)x_bytes)[i]), &max_val128)) { + max_val128 = *f128M_max(&max_val128, &((float128_t*)x_bytes)[i]); + max_idx = (len_x - i - 1); + } + } + break;} + } + + u3_noun r_data = u3i_chub(max_idx); + + return r_data; + } + +/* ravel - x -> ~[x[0], x[1], ... x[n]] + entire nd-array busted out as a linear list +*/ + u3_noun + u3qi_la_ravel_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // r_data is the result noun of [data] + u3_noun r_data = u3_nul; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + r_data = u3nc(u3i_word(x_val16.v), r_data); + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + r_data = u3nc(u3i_word(x_val32.v), r_data); + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + r_data = u3nc(u3i_chub(x_val64.v), r_data); + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + r_data = u3nc(u3i_chubs(2, (c3_d*)&(x_val128.v)), r_data); + } + break; + } + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* min - min(x,y) +*/ + u3_noun + u3qi_la_min_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by for range) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + + u3_noun r_data; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t min_val16 = ((float16_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + min_val16 = f16_min(min_val16, ((float16_t*)x_bytes)[i]); + } + float16_t r16[2]; + r16[0] = min_val16; + r16[1].v = 0x1; + r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)r16); + break;} + + case 5: { + float32_t min_val32 = ((float32_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + min_val32 = f32_min(min_val32, ((float32_t*)x_bytes)[i]); + } + float32_t r32[2]; + r32[0] = min_val32; + r32[1].v = 0x1; + r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)r32); + break;} + + case 6: { + float64_t min_val64 = ((float64_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + min_val64 = f64_min(min_val64, ((float64_t*)x_bytes)[i]); + } + float64_t r64[2]; + r64[0] = min_val64; + r64[1].v = 0x1; + r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)r64); + break;} + + case 7: { + float128_t min_val128 = ((float128_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + min_val128 = *f128M_min(&min_val128, &((float128_t*)x_bytes)[i]); + } + float128_t r128[2]; + r128[0] = min_val128; + r128[1] = (float128_t){0x1, 0x0}; + r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)r128); + break;} + } + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* max - max(x,y) +*/ + u3_noun + u3qi_la_max_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by for range) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + + u3_noun r_data; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t max_val16 = ((float16_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + max_val16 = f16_max(max_val16, ((float16_t*)x_bytes)[i]); + } + float16_t r16[2]; + r16[0] = max_val16; + r16[1].v = 0x1; + r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)r16); + break;} + + case 5: { + float32_t max_val32 = ((float32_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + max_val32 = f32_max(max_val32, ((float32_t*)x_bytes)[i]); + } + float32_t r32[2]; + r32[0] = max_val32; + r32[1].v = 0x1; + r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)r32); + break;} + + case 6: { + float64_t max_val64 = ((float64_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + max_val64 = f64_max(max_val64, ((float64_t*)x_bytes)[i]); + } + float64_t r64[2]; + r64[0] = max_val64; + r64[1].v = 0x1; + r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)r64); + break;} + + case 7: { + float128_t max_val128 = ((float128_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + max_val128 = *f128M_max(&max_val128, &((float128_t*)x_bytes)[i]); + } + float128_t r128[2]; + r128[0] = max_val128; + r128[1] = (float128_t){0x1, 0x0}; + r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)r128); + break;} + } + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* abs - |x| +*/ + u3_noun + u3qi_la_abs_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by for range) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + ((float16_t*)x_bytes)[i] = f16_abs(((float16_t*)x_bytes)[i]); + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + ((float32_t*)x_bytes)[i] = f32_abs(((float32_t*)x_bytes)[i]); + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + ((float64_t*)x_bytes)[i] = f64_abs(((float64_t*)x_bytes)[i]); + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + ((float128_t*)x_bytes)[i] = f128_abs(((float128_t*)x_bytes)[i]); + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes); + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* gth - x > y +*/ + u3_noun + u3qi_la_gth_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + float16_t y_val16 = ((float16_t*)y_bytes)[i]; + ((float16_t*)y_bytes)[i] = f16_gt(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO}; + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + float32_t y_val32 = ((float32_t*)y_bytes)[i]; + ((float32_t*)y_bytes)[i] = f32_gt(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO}; + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + float64_t y_val64 = ((float64_t*)y_bytes)[i]; + ((float64_t*)y_bytes)[i] = f64_gt(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO}; + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + float128_t y_val128 = ((float128_t*)y_bytes)[i]; + ((float128_t*)y_bytes)[i] = f128M_gt(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO}; + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* gte - x > y +*/ + u3_noun + u3qi_la_gte_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + float16_t y_val16 = ((float16_t*)y_bytes)[i]; + ((float16_t*)y_bytes)[i] = f16_ge(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO}; + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + float32_t y_val32 = ((float32_t*)y_bytes)[i]; + ((float32_t*)y_bytes)[i] = f32_ge(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO}; + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + float64_t y_val64 = ((float64_t*)y_bytes)[i]; + ((float64_t*)y_bytes)[i] = f64_ge(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO}; + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + float128_t y_val128 = ((float128_t*)y_bytes)[i]; + ((float128_t*)y_bytes)[i] = f128M_ge(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO}; + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* lth - x > y +*/ + u3_noun + u3qi_la_lth_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + float16_t y_val16 = ((float16_t*)y_bytes)[i]; + ((float16_t*)y_bytes)[i] = f16_lt(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO}; + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + float32_t y_val32 = ((float32_t*)y_bytes)[i]; + ((float32_t*)y_bytes)[i] = f32_lt(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO}; + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + float64_t y_val64 = ((float64_t*)y_bytes)[i]; + ((float64_t*)y_bytes)[i] = f64_lt(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO}; + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + float128_t y_val128 = ((float128_t*)y_bytes)[i]; + ((float128_t*)y_bytes)[i] = f128M_lt(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO}; + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* lte - x > y +*/ + u3_noun + u3qi_la_lte_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + float16_t y_val16 = ((float16_t*)y_bytes)[i]; + ((float16_t*)y_bytes)[i] = f16_le(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO}; + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + float32_t y_val32 = ((float32_t*)y_bytes)[i]; + ((float32_t*)y_bytes)[i] = f32_le(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO}; + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + float64_t y_val64 = ((float64_t*)y_bytes)[i]; + ((float64_t*)y_bytes)[i] = f64_le(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO}; + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + float128_t y_val128 = ((float128_t*)y_bytes)[i]; + ((float128_t*)y_bytes)[i] = f128M_le(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO}; + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* adds - axpy = 1*x+[n] +*/ + u3_noun + u3qi_la_adds_i754(u3_noun x_data, + u3_noun n, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + + float16_t n16; + float32_t n32; + float64_t n64; + float128_t n128; + + // Switch on the block size. We assume that n fits in the target block size; Hoon typecheck should prevent. + switch (u3x_atom(bloq)) { + case 4: + u3r_bytes(0, 2, (c3_y*)&(n16.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float16_t*)y_bytes)[i] = n16; + } + haxpy(len_x, (float16_t){SB_REAL16_ONE}, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1); + break; + + case 5: + u3r_bytes(0, 4, (c3_y*)&(n32.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float32_t*)y_bytes)[i] = n32; + } + saxpy(len_x, (float32_t){SB_REAL32_ONE}, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1); + break; + + case 6: + u3r_bytes(0, 8, (c3_y*)&(n64.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float64_t*)y_bytes)[i] = n64; + } + daxpy(len_x, (float64_t){SB_REAL64_ONE}, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1); + break; + + case 7: + u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float128_t*)y_bytes)[i] = (float128_t){n128.v[0], n128.v[1]}; + } + qaxpy(len_x, (float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1); + break; + } + + // r_data is the result noun of [data] + y_bytes[syz_x] = 0x1; // pin head + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* subs - axpy = -1*[n]+x +*/ + u3_noun + u3qi_la_subs_i754(u3_noun x_data, + u3_noun n, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/o leading 0x1) + c3_y* y_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + + float16_t n16; + float32_t n32; + float64_t n64; + float128_t n128; + + // Switch on the block size. We assume that n fits in the target block size; Hoon typecheck should prevent. + switch (u3x_atom(bloq)) { + case 4: + u3r_bytes(0, 2, (c3_y*)&(n16.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float16_t*)y_bytes)[i] = n16; + } + haxpy(len_x, (float16_t){SB_REAL16_NEGONE}, (float16_t*)y_bytes, 1, (float16_t*)x_bytes, 1); + break; + + case 5: + u3r_bytes(0, 4, (c3_y*)&(n32.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float32_t*)y_bytes)[i] = n32; + } + saxpy(len_x, (float32_t){SB_REAL32_NEGONE}, (float32_t*)y_bytes, 1, (float32_t*)x_bytes, 1); + break; + + case 6: + u3r_bytes(0, 8, (c3_y*)&(n64.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float64_t*)y_bytes)[i] = n64; + } + daxpy(len_x, (float64_t){SB_REAL64_NEGONE}, (float64_t*)y_bytes, 1, (float64_t*)x_bytes, 1); + break; + + case 7: + u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float128_t*)y_bytes)[i] = (float128_t){n128.v[0], n128.v[1]}; + } + qaxpy(len_x, (float128_t){SB_REAL128L_NEGONE,SB_REAL128U_NEGONE}, (float128_t*)y_bytes, 1, (float128_t*)x_bytes, 1); + break; + } + + // r_data is the result noun of [data] + x_bytes[syz_x] = 0x1; // pin head + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* muls - ?scal n * x + elementwise multiplication +*/ + u3_noun + u3qi_la_muls_i754(u3_noun x_data, + u3_noun n, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + x_bytes[syz_x] = 0x1; // pin head + + float16_t n16; + float32_t n32; + float64_t n64; + float128_t n128; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + u3r_bytes(0, 2, (c3_y*)&(n16.v), n); + hscal(len_x, n16, (float16_t*)x_bytes, 1); + break; + + case 5: + u3r_bytes(0, 4, (c3_y*)&(n32.v), n); + sscal(len_x, n32, (float32_t*)x_bytes, 1); + break; + + case 6: + u3r_bytes(0, 8, (c3_y*)&(n64.v), n); + dscal(len_x, n64, (float64_t*)x_bytes, 1); + break; + + case 7: + u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n); + qscal(len_x, n128, (float128_t*)x_bytes, 1); + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes); + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* divs - ?scal 1/n * x + elementwise division +*/ + u3_noun + u3qi_la_divs_i754(u3_noun x_data, + u3_noun n, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + x_bytes[syz_x] = 0x1; // pin head + + float16_t in16; + float32_t in32; + float64_t in64; + float128_t in128; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + // XX note that in16 is doing double duty here + u3r_bytes(0, 2, (c3_y*)&(in16.v), n); + in16 = f16_div((float16_t){SB_REAL16_ONE}, in16); + hscal(len_x, in16, (float16_t*)x_bytes, 1); + break; + + case 5: + // XX note that in32 is doing double duty here + u3r_bytes(0, 4, (c3_y*)&(in32.v), n); + in32 = f32_div((float32_t){SB_REAL32_ONE}, in32); + sscal(len_x, in32, (float32_t*)x_bytes, 1); + break; + + case 6: + // XX note that in64 is doing double duty here + u3r_bytes(0, 8, (c3_y*)&(in64.v), n); + in64 = f64_div((float64_t){SB_REAL64_ONE}, in64); + dscal(len_x, in64, (float64_t*)x_bytes, 1); + break; + + case 7: + // XX note that in128 is doing double duty here + u3r_bytes(0, 16, (c3_y*)&(in128.v[0]), n); + f128M_div(&((float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}), &in128, &in128); + qscal(len_x, in128, (float128_t*)x_bytes, 1); + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes); + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* mods - x % [n] = x - r*floor(x/r) + remainder after scalar division +*/ + u3_noun + u3qi_la_mods_i754(u3_noun x_data, + u3_noun n, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + // we reuse it for results for parsimony + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + + float16_t n16, in16; + float32_t n32, in32; + float64_t n64, in64; + float128_t n128, in128; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + u3r_bytes(0, 2, (c3_y*)&(n16.v), n); + in16 = f16_div((float16_t){SB_REAL16_ONE}, n16); + + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + // Perform division x/n + float16_t div_result16 = f16_mul(in16, x_val16); + // Compute floor of the division result + c3_ds floor_result16 = f16_to_i64(div_result16, softfloat_round_minMag, false); + float16_t floor_float16 = i64_to_f16(floor_result16); + // Multiply n by floor(x/n) + float16_t mult_result16 = f16_mul(n16, floor_float16); + // Compute remainder: x - n * floor(x/n) + ((float16_t*)x_bytes)[i] = f16_sub(x_val16, mult_result16); + } + break; + + case 5: + u3r_bytes(0, 4, (c3_y*)&(n32.v), n); + in32 = f32_div((float32_t){SB_REAL32_ONE}, n32); + + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + // Perform division x/n + float32_t div_result32 = f32_mul(in32, x_val32); + // Compute floor of the division result + c3_ds floor_result32 = f32_to_i64(div_result32, softfloat_round_minMag, false); + float32_t floor_float32 = i64_to_f32(floor_result32); + // Multiply n by floor(x/n) + float32_t mult_result32 = f32_mul(n32, floor_float32); + // Compute remainder: x - n * floor(x/n) + ((float32_t*)x_bytes)[i] = f32_sub(x_val32, mult_result32); + } + break; + + case 6: + u3r_bytes(0, 8, (c3_y*)&(n64.v), n); + in64 = f64_div((float64_t){SB_REAL64_ONE}, n64); + + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + // Perform division x/n + float64_t div_result64 = f64_mul(in64, x_val64); + // Compute floor of the division result + c3_ds floor_result64 = f64_to_i64(div_result64, softfloat_round_minMag, false); + float64_t floor_float64 = i64_to_f64(floor_result64); + // Multiply n by floor(x/n) + float64_t mult_result64 = f64_mul(n64, floor_float64); + // Compute remainder: x - n * floor(x/n) + ((float64_t*)x_bytes)[i] = f64_sub(x_val64, mult_result64); + } + break; + + case 7: + u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n); + f128M_div(&((float128_t){SB_REAL128L_ONE,SB_REAL128U_ZERO}), &n128, &in128); + + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + // Perform division x/n + float128_t div_result128; + f128M_mul((float128_t*)&in128, (float128_t*)&x_val128, (float128_t*)&div_result128); + // Compute floor of the division result + c3_ds floor_result128 = f128M_to_i64(&div_result128, softfloat_round_minMag, false); + float128_t floor_float128; + i64_to_f128M(floor_result128, &floor_float128); + // Multiply n by floor(x/n) + float128_t mult_result128; + f128M_mul(((float128_t*)&n128), ((float128_t*)&floor_float128), ((float128_t*)&mult_result128)); + // Compute remainder: x - n * floor(x/n) + f128M_sub(((float128_t*)&x_val128), ((float128_t*)&mult_result128), &(((float128_t*)x_bytes)[i])); + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes); + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* dot - ?dot = x · y +*/ + u3_noun + u3qi_la_dot_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + u3_noun r_data; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t r16[2]; + r16[0] = hdot(len_x, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1); + r16[1].v = 0x1; + r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)r16); + break;} + + case 5: { + float32_t r32[2]; + r32[0] = sdot(len_x, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1); + r32[1].v = 0x1; + r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)r32); + break;} + + case 6: { + float64_t r64[2]; + r64[0] = ddot(len_x, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1); + r64[1].v = 0x1; + r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)r64); + break;} + + case 7: { + float128_t r128[2]; + r128[0] = qdot(len_x, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1); + r128[1] = (float128_t){0x1, 0x0}; + r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)r128); + break;} + } + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* diag - diag(x) +*/ + u3_noun + u3qi_la_diag(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + // Assert length of dims is 2. + if (u3qb_lent(shape) != 2) { + return u3m_bail(c3__exit); + } + // Unpack shape into an array of dimensions. + c3_d *dims = _get_dims(shape); + if (dims[0] != dims[1]) { + return u3m_bail(c3__exit); + } + + // Unpack the data as a byte array. We assume total length < 2**64. + c3_d len_x = _get_length(shape); + c3_d syz_x = len_x * pow(2, bloq - 3); + c3_d wyd = pow(2, bloq - 3); + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + c3_d syz_y = wyd * dims[1]; + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_y+1)*sizeof(c3_y)); + + u3_noun r_data; + + // Grab the index at i*n_x+j in bytes; put it at j. + for (c3_d i = 0; i < dims[1]; i++) { + // Scan across whole field width. + for (c3_y k = 0; k < wyd; k++) { + y_bytes[i*wyd+k] = x_bytes[(i*dims[0]+i)*wyd+k]; + } + } + y_bytes[syz_y] = 0x1; // pin head + + // Unpack the result back into a noun. + r_data = u3i_bytes((syz_y+1)*sizeof(c3_y), y_bytes); + + u3a_free(x_bytes); + u3a_free(y_bytes); + u3a_free(dims); + + return r_data; + } + +/* transpose - x' +*/ + u3_noun + u3qi_la_transpose(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Assert length of dims is 2. + if (u3qb_lent(shape) != 2) { + return u3m_bail(c3__exit); + } + // Unpack shape into an array of dimensions. + c3_d *dims = _get_dims(shape); + + // Unpack the data as a byte array. We assume total length < 2**64. + c3_d len_x = _get_length(shape); + c3_d syz_x = len_x * pow(2, bloq - 3); + c3_d wyd = pow(2, bloq - 3); + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + + u3_noun r_data; + + // Grab the index at i*n_x+j in bytes; put it at j. + for (c3_d i = 0; i < dims[1]; i++) { + for (c3_d j = 0; j < dims[0]; j++) { + // Scan across whole field width. + for (c3_y k = 0; k < wyd; k++) { + y_bytes[(j*dims[1]+i)*wyd+k] = x_bytes[(i*dims[0]+j)*wyd+k]; + } + } + } + y_bytes[syz_x] = 0x1; // pin head + + // Unpack the result back into a noun. + r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + u3a_free(x_bytes); + u3a_free(y_bytes); + u3a_free(dims); + + return r_data; + } + +/* linspace - [a a+(b-a)/n ... b] +*/ + u3_noun + u3qi_la_linspace_i754(u3_noun a, + u3_noun b, + u3_noun n, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + u3_noun r_data; + + switch (u3x_atom(bloq)) { + case 4: { + float16_t a16, b16; + u3r_bytes(0, 2, (c3_y*)&(a16.v), a); + u3r_bytes(0, 2, (c3_y*)&(b16.v), b); + float16_t span16 = f16_sub(b16, a16); + float16_t interval16 = f16_div(span16, i32_to_f16(n-1)); + c3_y* x_bytes16 = (c3_y*)u3a_malloc((n*2+1)*sizeof(c3_y)); + for (c3_d i = 1; i < n-1; i++) { + ((float16_t*)x_bytes16)[i] = f16_add(a16, f16_mul(i32_to_f16(i), interval16)); + } + // Assign in reverse order so that n=1 case is correctly left-hand bound. + ((float16_t*)x_bytes16)[n-1] = b16; + ((float16_t*)x_bytes16)[0] = a16; + x_bytes16[n*2] = 0x1; // pin head + r_data = u3i_bytes((n*2+1)*sizeof(c3_y), x_bytes16); + u3a_free(x_bytes16); + break;} + + case 5: { + float32_t a32, b32; + u3r_bytes(0, 4, (c3_y*)&(a32.v), a); + u3r_bytes(0, 4, (c3_y*)&(b32.v), b); + float32_t span32 = f32_sub(b32, a32); + float32_t interval32 = f32_div(span32, i32_to_f32(n-1)); + c3_y* x_bytes32 = (c3_y*)u3a_malloc((n*4+1)*sizeof(c3_y)); + for (c3_d i = 1; i < n-1; i++) { + ((float32_t*)x_bytes32)[i] = f32_add(a32, f32_mul(i32_to_f32(i), interval32)); + } + ((float32_t*)x_bytes32)[n-1] = b32; + ((float32_t*)x_bytes32)[0] = a32; + x_bytes32[n*4] = 0x1; // pin head + r_data = u3i_bytes((n*4+1)*sizeof(c3_y), x_bytes32); + u3a_free(x_bytes32); + break;} + + case 6: { + float64_t a64, b64; + u3r_bytes(0, 8, (c3_y*)&(a64.v), a); + u3r_bytes(0, 8, (c3_y*)&(b64.v), b); + float64_t span64 = f64_sub(b64, a64); + float64_t interval64 = f64_div(span64, i32_to_f64(n-1)); + c3_y* x_bytes64 = (c3_y*)u3a_malloc((n*8+1)*sizeof(c3_y)); + for (c3_d i = 1; i < n-1; i++) { + ((float64_t*)x_bytes64)[i] = f64_add(a64, f64_mul(i32_to_f64(i), interval64)); + } + ((float64_t*)x_bytes64)[n-1] = b64; + ((float64_t*)x_bytes64)[0] = a64; + x_bytes64[n*8] = 0x1; // pin head + r_data = u3i_bytes((n*8+1)*sizeof(c3_y), x_bytes64); + u3a_free(x_bytes64); + break;} + + case 7: { + float128_t a128, b128; + u3r_bytes(0, 16, (c3_y*)&(a128.v[0]), a); + u3r_bytes(0, 16, (c3_y*)&(b128.v[0]), b); + float128_t span128; + f128M_sub(&b128, &a128, &span128); + float128_t interval128; + float128_t n128; + i32_to_f128M(n-1, &n128); + f128M_div(&span128, &n128, &interval128); + c3_y* x_bytes128 = (c3_y*)u3a_malloc((n*16+1)*sizeof(c3_y)); + float128_t i128; + for (c3_d i = 1; i < n-1; i++) { + i32_to_f128M(i, &i128); + f128M_mul(&i128, &interval128, &((float128_t*)x_bytes128)[i]); + f128M_add(&a128, &((float128_t*)x_bytes128)[i], &((float128_t*)x_bytes128)[i]); + } + ((float128_t*)x_bytes128)[n-1] = b128; + ((float128_t*)x_bytes128)[0] = a128; + x_bytes128[n*16] = 0x1; // pin head + r_data = u3i_bytes((n*16+1)*sizeof(c3_y), x_bytes128); + u3a_free(x_bytes128); + break;} + } + + return r_data; + } + +/* range - [a a+d ... b] +*/ + u3_noun + u3qi_la_range_i754(u3_noun a, + u3_noun b, + u3_noun d, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + u3_noun r_data; + + switch (u3x_atom(bloq)) { + case 4: { + float16_t a16, b16, interval16; + u3r_bytes(0, 2, (c3_y*)&(a16.v), a); + u3r_bytes(0, 2, (c3_y*)&(b16.v), b); + u3r_bytes(0, 2, (c3_y*)&(interval16.v), d); + c3_d n16 = f16_to_i64(f16_ceil(f16_div(f16_sub(b16, a16), interval16)), softfloat_round_minMag, false); + c3_y* x_bytes16 = (c3_y*)u3a_malloc(((n16+1)*2)*sizeof(c3_y)); + ((float16_t*)x_bytes16)[0] = a16; + for (c3_d i = 1; i < n16; i++) { + ((float16_t*)x_bytes16)[i] = f16_add(a16, f16_mul(i32_to_f16(i), interval16)); + } + ((float16_t*)x_bytes16)[n16].v = 0x1; // pin head + r_data = u3i_bytes(((n16+1)*2)*sizeof(c3_y), x_bytes16); + u3a_free(x_bytes16); + break;} + + case 5: { + float32_t a32, b32, interval32; + u3r_bytes(0, 4, (c3_y*)&(a32.v), a); + u3r_bytes(0, 4, (c3_y*)&(b32.v), b); + u3r_bytes(0, 4, (c3_y*)&(interval32.v), d); + c3_d n32 = f32_to_i64(f32_ceil(f32_div(f32_sub(b32, a32), interval32)), softfloat_round_minMag, false); + c3_y* x_bytes32 = (c3_y*)u3a_malloc(((n32+1)*4)*sizeof(c3_y)); + ((float32_t*)x_bytes32)[0] = a32; + for (c3_d i = 1; i < n32; i++) { + ((float32_t*)x_bytes32)[i] = f32_add(a32, f32_mul(i32_to_f32(i), interval32)); + } + ((float32_t*)x_bytes32)[n32].v = 0x1; // pin head + r_data = u3i_bytes(((n32+1)*4)*sizeof(c3_y), x_bytes32); + u3a_free(x_bytes32); + break;} + + case 6: { + float64_t a64, b64, interval64; + u3r_bytes(0, 8, (c3_y*)&(a64.v), a); + u3r_bytes(0, 8, (c3_y*)&(b64.v), b); + u3r_bytes(0, 8, (c3_y*)&(interval64.v), d); + c3_d n64 = f64_to_i64(f64_ceil(f64_div(f64_sub(b64, a64), interval64)), softfloat_round_minMag, false); + c3_y* x_bytes64 = (c3_y*)u3a_malloc(((n64+1)*8)*sizeof(c3_y)); + ((float64_t*)x_bytes64)[0] = a64; + for (c3_d i = 1; i < n64; i++) { + ((float64_t*)x_bytes64)[i] = f64_add(a64, f64_mul(i32_to_f64(i), interval64)); + } + ((float64_t*)x_bytes64)[n64].v = 0x1; // pin head + r_data = u3i_bytes(((n64+1)*8)*sizeof(c3_y), x_bytes64); + u3a_free(x_bytes64); + break;} + + case 7: { + float128_t a128, b128, interval128; + u3r_bytes(0, 16, (c3_y*)&(a128.v[0]), a); + u3r_bytes(0, 16, (c3_y*)&(b128.v[0]), b); + u3r_bytes(0, 16, (c3_y*)&(interval128.v[0]), d); + float128_t tmp; + f128M_sub(&b128, &a128, &tmp); + f128M_div(&tmp, &interval128, &tmp); + f128M_ceil(&tmp, &tmp); + c3_d n128 = f128M_to_i64(&tmp, softfloat_round_minMag, false); + c3_y* x_bytes128 = (c3_y*)u3a_malloc(((n128+1)*16)*sizeof(c3_y)); + float128_t i128; + ((float128_t*)x_bytes128)[0] = a128; + for (c3_d i = 1; i < n128; i++) { + i32_to_f128M(i, &i128); + f128M_mul(&i128, &interval128, &((float128_t*)x_bytes128)[i]); + f128M_add(&a128, &((float128_t*)x_bytes128)[i], &((float128_t*)x_bytes128)[i]); + } + ((float128_t*)x_bytes128)[n128].v[0] = 0x1; // pin head + ((float128_t*)x_bytes128)[n128].v[1] = 0x0; // pin head + r_data = u3i_bytes(((n128+1)*16)*sizeof(c3_y), x_bytes128); + u3a_free(x_bytes128); + break;} + } + + return r_data; + } + +/* trace - tr(x) +*/ + u3_noun + u3qi_la_trace_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + u3_noun d_data = u3qi_la_diag(x_data, shape, bloq); + c3_d len_x0 = _get_dims(shape)[0]; + u3_noun r_data = u3qi_la_dot_i754(d_data, d_data, u3nt(len_x0, 0x1, u3_nul), u3k(bloq)); + return r_data; + } + +/* mmul +*/ + u3_noun + u3qi_la_mmul_i754(u3_noun x_data, + u3_noun y_data, + u3_noun x_shape, + u3_noun y_shape, + u3_noun bloq) + { + // Unpack the data as a byte array. We assume total length < 2**64. + c3_d M = u3x_atom(u3h(x_shape)); + c3_d Na= u3x_atom(u3h(u3t(x_shape))); + c3_d Nb= u3x_atom(u3h(y_shape)); + c3_d P = u3x_atom(u3h(u3t(y_shape))); + + if ((u3_nul != u3t(u3t(x_shape))) || + (u3_nul != u3t(u3t(y_shape))) || + (Na != Nb)) { + return u3m_bail(c3__exit); + } + c3_d N = Na; + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(x_shape); // M*N + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); // M*N + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // len_x is length in base units + c3_d len_y = _get_length(y_shape); // N*P + + // syz_x is length in bytes + c3_d syz_y = len_y * pow(2, bloq-3); // N*P + + // y_bytes is the data array (w/o leading 0x1) + c3_y* y_bytes = (c3_y*)u3a_malloc(syz_y*sizeof(c3_y)); + u3r_bytes(0, syz_y, y_bytes, y_data); + + // len_r is length in base units + c3_d len_r = M*P; // M*P + + // syz_r is length in bytes + c3_d syz_r = len_r * pow(2, bloq-3); // M*P + + // r_bytes is the result array + c3_y* r_bytes = (c3_y*)u3a_malloc((syz_r+1)*sizeof(c3_y)); + r_bytes[syz_r] = 0x1; // pin head + // initialize with 0x0s + for (c3_d i = 0; i < syz_r; i++) { + r_bytes[i] = 0x0; + } + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + hgemm('N', 'N', M, N, P, (float16_t){SB_REAL16_ONE}, (float16_t*)x_bytes, N, (float16_t*)y_bytes, P, (float16_t){SB_REAL16_ZERO}, (float16_t*)r_bytes, P); + break; + + case 5: + sgemm('N', 'N', M, N, P, (float32_t){SB_REAL32_ONE}, (float32_t*)x_bytes, N, (float32_t*)y_bytes, P, (float32_t){SB_REAL32_ZERO}, (float32_t*)r_bytes, P); + break; + + case 6: + dgemm('N', 'N', M, N, P, (float64_t){SB_REAL64_ONE}, (float64_t*)x_bytes, N, (float64_t*)y_bytes, P, (float64_t){SB_REAL64_ZERO}, (float64_t*)r_bytes, P); + break; + + case 7: + qgemm('N', 'N', M, N, P, (float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}, (float128_t*)x_bytes, N, (float128_t*)y_bytes, P, (float128_t){SB_REAL128L_ZERO,SB_REAL128U_ZERO}, (float128_t*)r_bytes, P); + break; + } + + // Unpack the result back into a noun. + u3_noun r_data = u3i_bytes(syz_r+1, r_bytes); + u3_noun M_ = u3i_chub(M); + u3_noun P_ = u3i_chub(P); + + u3a_free(x_bytes); + u3a_free(y_bytes); + u3a_free(r_bytes); + + return u3nc(u3nq(u3nt(M_, P_, u3_nul), u3k(bloq), c3__i754, u3_nul), r_data); + } + + u3_noun + u3wi_la_add(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(rnd) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_add_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_sub(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(rnd) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_sub_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_mul(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(rnd) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_mul_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_div(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(rnd) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_div_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_mod(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(rnd) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_mod_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_cumsum(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_cumsum_i754(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3nc(0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_argmin(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_argmin_i754(x_data, x_shape, x_bloq); + // bare atom (@ index) + return r_data;} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_ravel(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_ravel_i754(x_data, x_shape, x_bloq); + // (list @) + return r_data;} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_argmax(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_argmax_i754(x_data, x_shape, x_bloq); + // bare atom (@ index) + return r_data;} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_min(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_min_i754(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3nt(0x1, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_max(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_max_i754(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3nt(0x1, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_abs(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_abs_i754(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_gth(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_gth_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3k(x_meta), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_gte(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_gte_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3k(x_meta), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_lth(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_lth_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3k(x_meta), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_lte(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_lte_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3k(x_meta), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_adds(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, n; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_3, &n, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(n) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_adds_i754(x_data, n, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + + u3_noun + u3wi_la_subs(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, n; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_3, &n, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(n) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_subs_i754(x_data, n, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + + u3_noun + u3wi_la_muls(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, n; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_3, &n, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(n) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_muls_i754(x_data, n, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + + u3_noun + u3wi_la_divs(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, n; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_3, &n, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(n) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_divs_i754(x_data, n, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + + u3_noun + u3wi_la_mods(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, n; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_3, &n, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(n) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_mods_i754(x_data, n, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + + u3_noun + u3wi_la_dot(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_dot_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + c3_d len_x0 = _get_dims(x_shape)[0]; + return u3nc(u3nq(u3nt(len_x0, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_transpose(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(cor) + ) + { + return u3m_bail(c3__exit); + } else { + u3_noun r_data = u3qi_la_transpose(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3nt(u3k(u3h(x_shape)), u3k(u3h(u3t(x_shape))), u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + } + } + } + + u3_noun + u3wi_la_linspace(u3_noun cor) + { + u3_noun x_meta, a, b, n, rnd; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_12, &a, + u3x_sam_13, &b, + u3x_sam_7, &n, + 0)) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(n) || + (n < 1) // crash on zero size + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_linspace_i754(a, b, n, x_bloq); + if (r_data == u3_none) { return u3_none; } + x_shape = u3nc(u3x_atom(n), u3_nul); + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_range(u3_noun cor) + { + u3_noun x_meta, a, b, d, rnd; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_12, &a, + u3x_sam_13, &b, + u3x_sam_7, &d, + 0)) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_range_i754(a, b, d, x_bloq); + if (r_data == u3_none) { return u3_none; } + c3_d a_, b_, d_; + c3_ds n_; + switch (x_bloq) { + case 4: + u3r_bytes(0, 2, (c3_y*)&a_, a); + u3r_bytes(0, 2, (c3_y*)&b_, b); + u3r_bytes(0, 2, (c3_y*)&d_, d); + n_ = f16_to_i64(f16_ceil(f16_div(f16_sub((float16_t){b_}, (float16_t){a_}), (float16_t){d_})), softfloat_round_minMag, false) - 1; + break; + case 5: + u3r_bytes(0, 4, (c3_y*)&a_, a); + u3r_bytes(0, 4, (c3_y*)&b_, b); + u3r_bytes(0, 4, (c3_y*)&d_, d); + n_ = f32_to_i64(f32_ceil(f32_div(f32_sub((float32_t){b_}, (float32_t){a_}), (float32_t){d_})), softfloat_round_minMag, false) - 1; + break; + case 6: + u3r_bytes(0, 8, (c3_y*)&a_, a); + u3r_bytes(0, 8, (c3_y*)&b_, b); + u3r_bytes(0, 8, (c3_y*)&d_, d); + n_ = f64_to_i64(f64_ceil(f64_div(f64_sub((float64_t){b_}, (float64_t){a_}), (float64_t){d_})), softfloat_round_minMag, false) - 1; + break; + case 7: { + c3_d a__[2], b__[2], d__[2]; + u3r_bytes(0, 16, (c3_y*)&a__, a); + u3r_bytes(0, 16, (c3_y*)&b__, b); + u3r_bytes(0, 16, (c3_y*)&d__, d); + float128_t tmp; + f128M_sub((float128_t*)&b__, (float128_t*)&a__, &tmp); + f128M_div(&tmp, (float128_t*)&d__, &tmp); + f128M_ceil(&tmp, &tmp); + n_ = f128M_to_i64(&tmp, softfloat_round_minMag, false) - 1; + break;} + } + u3_noun n = u3i_chub(n_+1); + x_shape = u3nc(u3k(n), u3_nul); + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_diag(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(cor) + ) + { + return u3m_bail(c3__exit); + } else { + u3_noun r_data = u3qi_la_diag(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + c3_d len_x0 = _get_dims(x_shape)[0]; + return u3nc(u3nq(u3nt(len_x0, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + } + } + } + + u3_noun + u3wi_la_trace(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + if ( c3n == u3r_mean(x_meta, + 2, &x_shape, + 6, &x_bloq, + 14, &x_kind, + 15, &x_tail, + 0) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_trace_i754(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3nt(0x1, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_mmul(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, + y_shape, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + y_shape = u3h(y_meta); // 2 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == _check(u3nc(x_meta, x_data)) || + c3n == _check(u3nc(y_meta, y_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_mmul_i754(x_data, y_data, x_shape, y_shape, x_bloq); + // result is already [meta data] + return r_data; + + default: + return u3_none; + } + } + } + } diff --git a/pkg/noun/jets/k.h b/pkg/noun/jets/k.h index f4587bef58..27733fb5e0 100644 --- a/pkg/noun/jets/k.h +++ b/pkg/noun/jets/k.h @@ -93,6 +93,11 @@ u3_weak u3kdb_put(u3_noun a, u3_noun b, u3_noun c); + /* u3kdb_del(): map del for key `b` + */ + u3_weak + u3kdb_del(u3_noun a, u3_noun b); + /* u3kdb_has(): test for get. */ u3_noun diff --git a/pkg/noun/jets/q.h b/pkg/noun/jets/q.h index b4fe7cd73e..a12d4766a8 100644 --- a/pkg/noun/jets/q.h +++ b/pkg/noun/jets/q.h @@ -54,13 +54,17 @@ u3_noun u3qc_can(u3_atom, u3_noun); u3_noun u3qc_cap(u3_atom); u3_noun u3qc_cat(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_clz(u3_atom, u3_atom, u3_atom); u3_noun u3qc_con(u3_atom, u3_atom); + u3_noun u3qc_ctz(u3_atom); u3_noun u3qc_cut(u3_atom, u3_atom, u3_atom, u3_atom); u3_noun u3qc_dis(u3_atom, u3_atom); u3_noun u3qc_dor(u3_atom, u3_atom); u3_noun u3qc_dvr(u3_atom, u3_atom); u3_noun u3qc_end(u3_atom, u3_atom, u3_atom); u3_noun u3qc_gor(u3_atom, u3_atom); + u3_noun u3qc_ham(u3_atom); + u3_noun u3qc_hew(u3_atom, u3_atom, u3_atom, u3_noun); u3_noun u3qc_lsh(u3_atom, u3_atom, u3_atom); u3_noun u3qc_mas(u3_atom); u3_noun u3qc_met(u3_atom, u3_atom); @@ -72,11 +76,14 @@ u3_noun u3qc_rap(u3_atom, u3_noun); u3_noun u3qc_rep(u3_atom, u3_atom, u3_noun); u3_noun u3qc_rev(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_rig(u3_atom, u3_atom, u3_atom); u3_noun u3qc_rip(u3_atom, u3_atom, u3_atom); u3_noun u3qc_rsh(u3_atom, u3_atom, u3_atom); u3_noun u3qc_swp(u3_atom, u3_atom); u3_noun u3qc_sqt(u3_atom); + c3_d u3qc_rig_s(c3_g, c3_w, c3_g); + u3_noun u3_po_find_prefix(c3_y one, c3_y two, c3_y three); u3_noun u3_po_find_suffix(c3_y one, c3_y two, c3_y three); void u3_po_to_prefix(u3_noun id, c3_y* a, c3_y* b, c3_y* c); @@ -88,6 +95,7 @@ u3_noun u3qdb_any(u3_noun, u3_noun); u3_noun u3qdb_apt(u3_noun); u3_noun u3qdb_bif(u3_noun, u3_noun); + u3_noun u3qdb_del(u3_noun, u3_noun); u3_noun u3qdb_dif(u3_noun, u3_noun); u3_noun u3qdb_gas(u3_noun, u3_noun); u3_noun u3qdb_get(u3_noun, u3_noun); @@ -103,6 +111,7 @@ u3_noun u3qdi_apt(u3_noun); u3_noun u3qdi_bif(u3_noun, u3_noun); + u3_noun u3qdi_del(u3_noun, u3_noun); u3_noun u3qdi_dif(u3_noun, u3_noun); u3_noun u3qdi_gas(u3_noun, u3_noun); u3_noun u3qdi_has(u3_noun, u3_noun); @@ -246,11 +255,46 @@ u3_noun u3qfp_nepo(u3_noun, u3_noun); u3_noun u3qfp_rake(u3_noun); + u3_noun u3qi_la_add_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_sub_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mul_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_div_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mod_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_adds_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_subs_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_muls_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_divs_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mods_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_dot_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_diag(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_transpose(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_cumsum_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_argmin_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_argmax_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_ravel_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_min_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_max_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_linspace_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_range_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_abs_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_gth_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_gte_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_lth_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_lte_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_trace_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mmul_i754(u3_noun, u3_noun, u3_noun, u3_noun, u3_noun); + # define u3qfu_van_fan 28 # define u3qfu_van_rib 58 # define u3qfu_van_vet 59 void u3qf_test(const c3_c*, u3_noun); + + /** Tier 6. + **/ + u3_noun u3qg_plot_fax(u3_noun, u3_noun); + u3_noun u3qg_plot_met(u3_noun, u3_noun); + #endif /* ifndef U3_JETS_Q_H */ diff --git a/pkg/noun/jets/tree.c b/pkg/noun/jets/tree.c index cd1e05aec1..59a93204bb 100644 --- a/pkg/noun/jets/tree.c +++ b/pkg/noun/jets/tree.c @@ -21,7 +21,6 @@ #include "jets.h" #include "jets/w.h" - static c3_c* no_hashes[] = { 0 }; @@ -275,13 +274,19 @@ static c3_c* _140_hex_coed__ed_puck_ha[] = { "1bc694675842345c50b0e20a2193bb5bcbb42f163fc832431a3d1822a81e4c98", 0 }; + static u3j_harm _140_hex_coed__ed_sign_a[] = {{".2", u3wee_sign}, {}}; -static c3_c* _140_hex_coed__ed_sign_ha[] = { + +static u3j_harm _140_hex_coed__ed_sign_octs_a[] = {{".2", u3wee_sign_octs}, {}}; +static c3_c* _140_hex_coed__ed_sign_octs_ha[] = { "34ad749bf8443611cbf1f7de90a066318bd12be36f2f7f6f55281f6f7ed79754", 0 }; + static u3j_harm _140_hex_coed__ed_veri_a[] = {{".2", u3wee_veri}, {}}; -static c3_c* _140_hex_coed__ed_veri_ha[] = { + +static u3j_harm _140_hex_coed__ed_veri_octs_a[] = {{".2", u3wee_veri_octs}, {}}; +static c3_c* _140_hex_coed__ed_veri_octs_ha[] = { "047a7eeccb2e68aeeee631b6db86e11a5a3aa9e179660553eca6304327612dcf", 0 }; @@ -323,9 +328,11 @@ static c3_c* _140_hex_coed__ed_shar_ha[] = { }; static u3j_core _140_hex_coed__ed_d[] = - { { "sign", 7, _140_hex_coed__ed_sign_a, 0, _140_hex_coed__ed_sign_ha }, + { { "sign", 7, _140_hex_coed__ed_sign_a, 0, no_hashes }, + { "sign-octs", 7, _140_hex_coed__ed_sign_octs_a, 0, _140_hex_coed__ed_sign_octs_ha }, { "puck", 7, _140_hex_coed__ed_puck_a, 0, _140_hex_coed__ed_puck_ha }, - { "veri", 7, _140_hex_coed__ed_veri_a, 0, _140_hex_coed__ed_veri_ha }, + { "veri", 7, _140_hex_coed__ed_veri_a, 0, no_hashes }, + { "veri-octs", 7, _140_hex_coed__ed_veri_octs_a, 0, _140_hex_coed__ed_veri_octs_ha }, { "shar", 7, _140_hex_coed__ed_shar_a, 0, _140_hex_coed__ed_shar_ha }, { "point-add", 7, _140_hex_coed__ed_point_add_a, 0, 0 }, { "scalarmult", 7, _140_hex_coed__ed_scalarmult_a, 0, @@ -495,14 +502,14 @@ static u3j_core _140_hex_d[] = { "coed", 63, 0, _140_hex_coed_d, _140_hex_coed_ha }, { "aes", 31, 0, _140_hex_aes_d, _140_hex_aes_ha }, - { "hmac", 63, 0, _140_hex_hmac_d, _140_hex_hmac_ha }, - { "argon", 31, 0, _140_hex_argon_d, _140_hex_argon_ha }, - { "blake", 31, 0, _140_hex_blake_d, _140_hex_blake_ha }, - { "kecc", 31, 0, _140_hex_kecc_d, no_hashes }, - { "ripemd", 31, 0, _140_hex_ripe_d, _140_hex_ripe_ha }, - { "scr", 31, 0, _140_hex_scr_d, _140_hex_scr_ha }, - { "secp", 6, 0, _140_hex_secp_d, _140_hex_secp_ha }, - { "mimes", 31, 0, _140_hex_mimes_d, _140_hex_mimes_ha }, + { "hmac", 63, 0, _140_hex_hmac_d, _140_hex_hmac_ha }, + { "argon", 31, 0, _140_hex_argon_d, _140_hex_argon_ha }, + { "blake", 31, 0, _140_hex_blake_d, _140_hex_blake_ha }, + { "kecc", 31, 0, _140_hex_kecc_d, no_hashes }, + { "ripemd", 31, 0, _140_hex_ripe_d, _140_hex_ripe_ha }, + { "scr", 31, 0, _140_hex_scr_d, _140_hex_scr_ha }, + { "secp", 6, 0, _140_hex_secp_d, _140_hex_secp_ha }, + { "mimes", 31, 0, _140_hex_mimes_d, _140_hex_mimes_ha }, {} }; static c3_c* _140_hex_ha[] = { @@ -2120,8 +2127,11 @@ static u3j_core _139_hex_json_d[] = {} }; + + static u3j_core _139_hex_d[] = -{ { "lore", 63, _140_hex_lore_a, 0, no_hashes }, +{ + { "lore", 63, _140_hex_lore_a, 0, no_hashes }, { "leer", 63, _140_hex_leer_a, 0, no_hashes }, { "loss", 63, _140_hex_loss_a, 0, no_hashes }, { "lune", 127, _140_hex_lune_a, 0, no_hashes }, @@ -2129,15 +2139,15 @@ static u3j_core _139_hex_d[] = { "coed", 63, 0, _140_hex_coed_d, no_hashes }, { "aes", 31, 0, _140_hex_aes_d, no_hashes }, - { "hmac", 63, 0, _140_hex_hmac_d, no_hashes }, - { "argon", 31, 0, _140_hex_argon_d, no_hashes }, - { "blake", 31, 0, _140_hex_blake_d, no_hashes }, - { "kecc", 31, 0, _140_hex_kecc_d, no_hashes }, - { "ripemd", 31, 0, _140_hex_ripe_d, no_hashes }, - { "scr", 31, 0, _140_hex_scr_d, no_hashes }, - { "secp", 6, 0, _140_hex_secp_d, no_hashes }, - { "mimes", 31, 0, _140_hex_mimes_d, no_hashes }, - { "json", 31, 0, _139_hex_json_d, no_hashes }, + { "hmac", 63, 0, _140_hex_hmac_d, no_hashes }, + { "argon", 31, 0, _140_hex_argon_d, no_hashes }, + { "blake", 31, 0, _140_hex_blake_d, no_hashes }, + { "kecc", 31, 0, _140_hex_kecc_d, no_hashes }, + { "ripemd", 31, 0, _140_hex_ripe_d, no_hashes }, + { "scr", 31, 0, _140_hex_scr_d, no_hashes }, + { "secp", 6, 0, _140_hex_secp_d, no_hashes }, + { "mimes", 31, 0, _140_hex_mimes_d, no_hashes }, + { "json", 31, 0, _139_hex_json_d, no_hashes }, {} }; @@ -2341,6 +2351,14 @@ static u3j_core _138_hex_blake_d[] = {} }; + static u3j_harm _138_hex_chacha_crypt_a[] = {{".2", u3we_chacha_crypt, c3y}, {}}; + static u3j_harm _138_hex_chacha_xchacha_a[] = {{".2", u3we_chacha_xchacha, c3y}, {}}; +static u3j_core _138_hex_chacha_d[] = + { { "crypt", 7, _138_hex_chacha_crypt_a, 0, no_hashes }, + { "xchacha", 7, _138_hex_chacha_xchacha_a, 0, no_hashes }, + {} + }; + static u3j_core _138_hex_d[] = { { "lore", 63, _140_hex_lore_a, 0, no_hashes }, { "leer", 63, _140_hex_leer_a, 0, no_hashes }, @@ -2350,15 +2368,16 @@ static u3j_core _138_hex_d[] = { "coed", 63, 0, _140_hex_coed_d, no_hashes }, { "aes", 31, 0, _140_hex_aes_d, no_hashes }, - { "hmac", 63, 0, _140_hex_hmac_d, no_hashes }, - { "argon", 31, 0, _140_hex_argon_d, no_hashes }, - { "blake", 31, 0, _138_hex_blake_d, no_hashes }, - { "kecc", 31, 0, _140_hex_kecc_d, no_hashes }, - { "ripemd", 31, 0, _140_hex_ripe_d, no_hashes }, - { "scr", 31, 0, _140_hex_scr_d, no_hashes }, - { "secp", 6, 0, _140_hex_secp_d, no_hashes }, - { "mimes", 31, 0, _140_hex_mimes_d, no_hashes }, - { "json", 31, 0, _139_hex_json_d, no_hashes }, + { "hmac", 63, 0, _140_hex_hmac_d, no_hashes }, + { "argon", 31, 0, _140_hex_argon_d, no_hashes }, + { "blake", 31, 0, _138_hex_blake_d, no_hashes }, + { "chacha", 31, 0, _138_hex_chacha_d, no_hashes }, + { "kecc", 31, 0, _140_hex_kecc_d, no_hashes }, + { "ripemd", 31, 0, _140_hex_ripe_d, no_hashes }, + { "scr", 31, 0, _140_hex_scr_d, no_hashes }, + { "secp", 6, 0, _140_hex_secp_d, no_hashes }, + { "mimes", 31, 0, _140_hex_mimes_d, no_hashes }, + { "json", 31, 0, _139_hex_json_d, no_hashes }, {} }; @@ -2549,14 +2568,12 @@ static u3j_core _138_one_d[] = {} }; -u3j_core _k138_d[] = +static u3j_core _k138_d[] = { { "one", 3, 0, _138_one_d, no_hashes }, {} }; -// TODO: probably need different ha hashes - static u3j_core _a50_two__by_d[] = { { "apt", 7, _140_two__by_apt_a, 0, _140_two__by_apt_ha }, { "del", 7, _140_two__by_del_a, 0, _140_two__by_del_ha }, @@ -2620,10 +2637,13 @@ u3j_core _a50_d[] = {} }; +extern u3j_core _k137_d[]; + static u3j_core _d[] = { { "k140", 0, 0, _k140_d, _k140_ha, 0, (u3j_core*) 140, 0 }, { "k139", 0, 0, _k139_d, no_hashes, 0, (u3j_core*) 139, 0 }, { "k138", 0, 0, _k138_d, no_hashes, 0, (u3j_core*) 138, 0 }, + { "k137", 0, 0, _k137_d, no_hashes, 0, (u3j_core*) 137, 0 }, { "a50", 0, 0, _a50_d, _k140_ha, 0, (u3j_core*) c3__a50, 0 }, {} }; diff --git a/pkg/noun/jets/w.h b/pkg/noun/jets/w.h index 275740cd97..78494314fe 100644 --- a/pkg/noun/jets/w.h +++ b/pkg/noun/jets/w.h @@ -56,13 +56,17 @@ u3_noun u3wc_can(u3_noun); u3_noun u3wc_cap(u3_noun); u3_noun u3wc_cat(u3_noun); + u3_noun u3wc_clz(u3_noun); u3_noun u3wc_con(u3_noun); + u3_noun u3wc_ctz(u3_noun); u3_noun u3wc_cut(u3_noun); u3_noun u3wc_dis(u3_noun); u3_noun u3wc_dor(u3_noun); u3_noun u3wc_dvr(u3_noun); u3_noun u3wc_end(u3_noun); u3_noun u3wc_gor(u3_noun); + u3_noun u3wc_ham(u3_noun); + u3_noun u3wc_hew(u3_noun); u3_noun u3wc_lsh(u3_noun); u3_noun u3wc_mas(u3_noun); u3_noun u3wc_met(u3_noun); @@ -75,6 +79,7 @@ u3_noun u3wc_rap(u3_noun); u3_noun u3wc_rep(u3_noun); u3_noun u3wc_rev(u3_noun); + u3_noun u3wc_rig(u3_noun); u3_noun u3wc_rip(u3_noun); u3_noun u3wc_rsh(u3_noun); u3_noun u3wc_swp(u3_noun); @@ -191,6 +196,8 @@ u3_noun u3wee_puck(u3_noun); u3_noun u3wee_sign(u3_noun); u3_noun u3wee_veri(u3_noun); + u3_noun u3wee_sign_octs(u3_noun); + u3_noun u3wee_veri_octs(u3_noun); u3_noun u3wee_shar(u3_noun); u3_noun u3wee_point_add(u3_noun); u3_noun u3wee_scalarmult(u3_noun); @@ -212,6 +219,9 @@ u3_noun u3we_blake3_chunk_output(u3_noun); u3_noun u3we_blake3_compress(u3_noun); + u3_noun u3we_chacha_crypt(u3_noun); + u3_noun u3we_chacha_xchacha(u3_noun); + u3_noun u3we_ripe(u3_noun); u3_noun u3we_make(u3_noun); @@ -292,6 +302,8 @@ u3_noun u3wes_gte(u3_noun); u3_noun u3wes_gth(u3_noun); + u3_noun u3we_crc32(u3_noun); + /** Tier 6. **/ u3_noun u3wf_bull(u3_noun); @@ -336,5 +348,39 @@ u3_noun u3wfu_repo(u3_noun); u3_noun u3wfu_rest(u3_noun); + /** Tier 7. + **/ + u3_noun u3wg_plot_fax(u3_noun); + u3_noun u3wg_plot_met(u3_noun); + u3_noun u3wi_la_add(u3_noun); + u3_noun u3wi_la_sub(u3_noun); + u3_noun u3wi_la_mul(u3_noun); + u3_noun u3wi_la_div(u3_noun); + u3_noun u3wi_la_mod(u3_noun); + u3_noun u3wi_la_adds(u3_noun); + u3_noun u3wi_la_subs(u3_noun); + u3_noun u3wi_la_muls(u3_noun); + u3_noun u3wi_la_divs(u3_noun); + u3_noun u3wi_la_mods(u3_noun); + u3_noun u3wi_la_dot(u3_noun); + u3_noun u3wi_la_diag(u3_noun); + u3_noun u3wi_la_transpose(u3_noun); + u3_noun u3wi_la_cumsum(u3_noun); + u3_noun u3wi_la_argmin(u3_noun); + u3_noun u3wi_la_argmax(u3_noun); + u3_noun u3wi_la_ravel(u3_noun); + u3_noun u3wi_la_min(u3_noun); + u3_noun u3wi_la_max(u3_noun); + u3_noun u3wi_la_linspace(u3_noun); + u3_noun u3wi_la_range(u3_noun); + u3_noun u3wi_la_abs(u3_noun); + u3_noun u3wi_la_gth(u3_noun); + u3_noun u3wi_la_gte(u3_noun); + u3_noun u3wi_la_lth(u3_noun); + u3_noun u3wi_la_lte(u3_noun); + + u3_noun u3wi_la_trace(u3_noun); + u3_noun u3wi_la_mmul(u3_noun); + #endif /* ifndef U3_JETS_W_H */ diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index 90b993469c..d167994a46 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -473,15 +473,17 @@ u3m_file(c3_c* pas_c) /* u3m_mark(): mark all nouns in the road. */ -c3_w -u3m_mark(FILE* fil_u) +u3m_quac** +u3m_mark(void) { - c3_w tot_w = 0; - tot_w += u3v_mark(fil_u); - tot_w += u3j_mark(fil_u); - tot_w += u3n_mark(fil_u); - tot_w += u3a_mark_road(fil_u); - return tot_w; + u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 5); + qua_u[0] = u3v_mark(); + qua_u[1] = u3j_mark(); + qua_u[2] = u3n_mark(); + qua_u[3] = u3a_mark_road(); + qua_u[4] = NULL; + + return qua_u; } /* _pave_parts(): build internal tables. @@ -1540,7 +1542,7 @@ u3m_grab(u3_noun som, ...) // terminate with u3_none // u3h_free(u3R->cax.har_p); // u3R->cax.har_p = u3h_new(); - u3m_mark(0); + u3m_mark(); { va_list vap; u3_noun tur; diff --git a/pkg/noun/manage.h b/pkg/noun/manage.h index 46a8bcb61e..8e543992b9 100644 --- a/pkg/noun/manage.h +++ b/pkg/noun/manage.h @@ -148,10 +148,19 @@ u3_noun u3m_soft_esc(u3_noun ref, u3_noun sam); + + /* u3m_quac: memory report. + */ + typedef struct _u3m_quac { + c3_c* nam_c; + c3_w siz_w; + struct _u3m_quac** qua_u; + } u3m_quac; + /* u3m_mark(): mark all nouns in the road. */ - c3_w - u3m_mark(FILE* fil_u); + u3m_quac** + u3m_mark(); /* u3m_grab(): garbage-collect the world, plus extra roots. */ diff --git a/pkg/noun/nock.c b/pkg/noun/nock.c index f9814a395f..076717b7ad 100644 --- a/pkg/noun/nock.c +++ b/pkg/noun/nock.c @@ -3058,16 +3058,30 @@ _n_bam(u3_noun kev, void* dat) /* u3n_mark(): mark the bytecode cache for gc. */ -c3_w -u3n_mark(FILE* fil_u) +u3m_quac* +u3n_mark() { - c3_w bam_w = 0, har_w = 0; + u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 3); + + qua_u[0] = c3_calloc(sizeof(*qua_u[0])); + qua_u[0]->nam_c = strdup("bytecode programs"); + u3p(u3h_root) har_p = u3R->byc.har_p; - u3h_walk_with(har_p, _n_bam, &bam_w); + u3h_walk_with(har_p, _n_bam, &qua_u[0]->siz_w); + qua_u[0]->siz_w = qua_u[0]->siz_w * 4; + + qua_u[1] = c3_calloc(sizeof(*qua_u[1])); + qua_u[1]->nam_c = strdup("bytecode cache"); + qua_u[1]->siz_w = u3h_mark(har_p) * 4; + + qua_u[2] = NULL; + + u3m_quac* tot_u = c3_malloc(sizeof(*tot_u)); + tot_u->nam_c = strdup("total nock stuff"); + tot_u->siz_w = qua_u[0]->siz_w + qua_u[1]->siz_w; + tot_u->qua_u = qua_u; - bam_w = u3a_maid(fil_u, " bytecode programs", bam_w); - har_w = u3a_maid(fil_u, " bytecode cache", u3h_mark(har_p)); - return u3a_maid(fil_u, "total nock stuff", bam_w + har_w); + return tot_u; } /* u3n_reclaim(): clear ad-hoc persistent caches to reclaim memory. diff --git a/pkg/noun/nock.h b/pkg/noun/nock.h index 3f1830a301..5c34515a02 100644 --- a/pkg/noun/nock.h +++ b/pkg/noun/nock.h @@ -123,8 +123,8 @@ /* u3n_mark(): mark bytecode cache. */ - c3_w - u3n_mark(FILE* fil_u); + u3m_quac* + u3n_mark(); /* u3n_reclaim(): clear ad-hoc persistent caches to reclaim memory. */ diff --git a/pkg/noun/ship.c b/pkg/noun/ship.c new file mode 100644 index 0000000000..6aebff71aa --- /dev/null +++ b/pkg/noun/ship.c @@ -0,0 +1,109 @@ +#include "c3/c3.h" +#include "types.h" +#include "imprison.h" +#include "retrieve.h" +#include "vortex.h" +#include "ship.h" + +static inline void +_s_chub_to_bytes(c3_y byt_y[8], c3_d num_d) +{ + byt_y[0] = num_d & 0xff; + byt_y[1] = (num_d >> 8) & 0xff; + byt_y[2] = (num_d >> 16) & 0xff; + byt_y[3] = (num_d >> 24) & 0xff; + byt_y[4] = (num_d >> 32) & 0xff; + byt_y[5] = (num_d >> 40) & 0xff; + byt_y[6] = (num_d >> 48) & 0xff; + byt_y[7] = (num_d >> 56) & 0xff; +} + +static inline c3_d +_s_bytes_to_chub(c3_y byt_y[8]) +{ + return (c3_d)byt_y[0] + | (c3_d)byt_y[1] << 8 + | (c3_d)byt_y[2] << 16 + | (c3_d)byt_y[3] << 24 + | (c3_d)byt_y[4] << 32 + | (c3_d)byt_y[5] << 40 + | (c3_d)byt_y[6] << 48 + | (c3_d)byt_y[7] << 56; +} + +void +u3_ship_to_bytes(u3_ship who_u, c3_y len_y, c3_y* buf_y) +{ + c3_y sip_y[16] = {0}; + + _s_chub_to_bytes(sip_y, who_u[0]); + _s_chub_to_bytes(sip_y + 8, who_u[1]); + + memcpy(buf_y, sip_y, c3_min(16, len_y)); +} + +void +u3_ship_of_bytes(u3_ship who_u, c3_y len_y, c3_y* buf_y) +{ + c3_y sip_y[16] = {0}; + memcpy(sip_y, buf_y, c3_min(16, len_y)); + + who_u[0] = _s_bytes_to_chub(sip_y); + who_u[1] = _s_bytes_to_chub(sip_y + 8); +} + +u3_atom +u3_ship_to_noun(u3_ship who_u) +{ + return u3i_chubs(2, who_u); +} + +c3_c* +u3_ship_to_string(u3_ship who_u) +{ + u3_noun ser = u3dc("scot", c3__p, u3_ship_to_noun(who_u)); + c3_c* who_c = u3r_string(ser); + u3z(ser); + return who_c; +} + +void +u3_ship_of_noun(u3_ship who_u, u3_noun who) +{ + u3r_chubs(0, 2, who_u, who); +} + +c3_o +u3_ships_equal(u3_ship sip_u, u3_ship sap_u) +{ + return __((sip_u[0] == sap_u[0]) && (sip_u[1] == sap_u[1])); +} + +void +u3_ship_copy(u3_ship des_u, u3_ship src_u) +{ + des_u[0] = src_u[0]; + des_u[1] = src_u[1]; +} + +c3_l +u3_ship_rank(u3_ship who_u) +{ + if ( who_u[1] ) return c3__pawn; + else if ( who_u[0] >> 32 ) return c3__earl; + else if ( who_u[0] >> 16 ) return c3__duke; + else if ( who_u[0] >> 8 ) return c3__king; + else return c3__czar; +} + +c3_y +u3_ship_czar(u3_ship who_u) { return who_u[0] & 0xFF; } + +c3_s +u3_ship_king(u3_ship who_u) { return who_u[0] & 0xffff; } + +c3_w +u3_ship_duke(u3_ship who_u) { return who_u[0] & 0xffffffff; } + +c3_d +u3_ship_earl(u3_ship who_u) { return who_u[0]; } diff --git a/pkg/noun/ship.h b/pkg/noun/ship.h new file mode 100644 index 0000000000..8104c42d5b --- /dev/null +++ b/pkg/noun/ship.h @@ -0,0 +1,57 @@ +#ifndef U3_SHIP_H +#define U3_SHIP_H + +#include "c3/c3.h" +#include "types.h" + +typedef c3_d u3_ship[2]; + +void +u3_ship_to_bytes(c3_d sip_d[2], c3_y len_y, c3_y* buf_y); + +void +u3_ship_of_bytes(u3_ship who_u, c3_y len_y, c3_y* buf_y); + +u3_atom +u3_ship_to_noun(u3_ship who_u); + +void +u3_ship_of_noun(u3_ship who_u, u3_noun who); + +c3_c* +u3_ship_to_string(u3_ship who_u); + +c3_o +u3_ships_equal(u3_ship sip_u, u3_ship sap_u); + +c3_l +u3_ship_rank(u3_ship who_u); + +void +u3_ship_copy(u3_ship des_u, u3_ship src_u); + +/** +* Returns a ship's galaxy byte prefix. +*/ +c3_y +u3_ship_czar(u3_ship who_u); + +/** +* Returns a ship's star prefix. +*/ +c3_s +u3_ship_king(u3_ship who_u); + +/** +* Returns a ship's planet prefix. +*/ +c3_w +u3_ship_duke(u3_ship who_u); + +/** +* Returns a ship's moon prefix. +*/ +c3_d +u3_ship_earl(u3_ship who_u); + +#endif /* ifndef U3_SHIP_H */ diff --git a/pkg/noun/vortex.c b/pkg/noun/vortex.c index cb95c8edc3..0abb61babc 100644 --- a/pkg/noun/vortex.c +++ b/pkg/noun/vortex.c @@ -384,16 +384,33 @@ u3v_sway(u3_noun blu, c3_l tab_l, u3_noun tax) /* u3v_mark(): mark arvo kernel. */ -c3_w -u3v_mark(FILE* fil_u) +u3m_quac* +u3v_mark() { u3v_arvo* arv_u = &(u3H->arv_u); - c3_w tot_w = 0; - tot_w += u3a_maid(fil_u, " kernel", u3a_mark_noun(arv_u->roc)); - tot_w += u3a_maid(fil_u, " date", u3a_mark_noun(arv_u->now)); - tot_w += u3a_maid(fil_u, " wish cache", u3a_mark_noun(arv_u->yot)); - return u3a_maid(fil_u, "total arvo stuff", tot_w); + u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 4); + + qua_u[0] = c3_calloc(sizeof(*qua_u[0])); + qua_u[0]->nam_c = strdup("kernel"); + qua_u[0]->siz_w = u3a_mark_noun(arv_u->roc) * 4; + + qua_u[1] = c3_calloc(sizeof(*qua_u[1])); + qua_u[1]->nam_c = strdup("date"); + qua_u[1]->siz_w = u3a_mark_noun(arv_u->now) * 4; + + qua_u[2] = c3_calloc(sizeof(*qua_u[2])); + qua_u[2]->nam_c = strdup("wish cache"); + qua_u[2]->siz_w = u3a_mark_noun(arv_u->yot) * 4; + + qua_u[3] = NULL; + + u3m_quac* tot_u = c3_malloc(sizeof(*tot_u)); + tot_u->nam_c = strdup("total arvo stuff"); + tot_u->siz_w = qua_u[0]->siz_w + qua_u[1]->siz_w + qua_u[2]->siz_w; + tot_u->qua_u = qua_u; + + return tot_u; } /* u3v_reclaim(): clear ad-hoc persistent caches to reclaim memory. @@ -426,4 +443,3 @@ u3v_rewrite_compact(void) arv_u->now = u3a_rewritten_noun(arv_u->now); arv_u->yot = u3a_rewritten_noun(arv_u->yot); } - diff --git a/pkg/noun/vortex.h b/pkg/noun/vortex.h index 9cc56474e0..5772543dcb 100644 --- a/pkg/noun/vortex.h +++ b/pkg/noun/vortex.h @@ -130,8 +130,8 @@ /* u3v_mark(): mark arvo kernel. */ - c3_w - u3v_mark(FILE* fil_u); + u3m_quac* + u3v_mark(); /* u3v_reclaim(): clear ad-hoc persistent caches to reclaim memory. */ diff --git a/pkg/vere/auto.c b/pkg/vere/auto.c index 2435458ad4..b2da91688e 100644 --- a/pkg/vere/auto.c +++ b/pkg/vere/auto.c @@ -439,6 +439,7 @@ u3_auto_init(u3_pier* pir_u) car_u = _auto_link(u3_term_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_fore_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_lick_io_init(pir_u), pir_u, car_u); + car_u = _auto_link(u3_mesa_io_init(pir_u), pir_u, car_u); return car_u; } diff --git a/pkg/vere/dawn.c b/pkg/vere/dawn.c index ba474d10d4..37758e553e 100644 --- a/pkg/vere/dawn.c +++ b/pkg/vere/dawn.c @@ -41,24 +41,6 @@ _dawn_buf_to_oct(uv_buf_t buf_u) return u3nc(len, u3i_bytes(buf_u.len, (const c3_y*)buf_u.base)); } - -/* _dawn_curl_alloc(): allocate a response buffer for curl -*/ -static size_t -_dawn_curl_alloc(void* dat_v, size_t uni_t, size_t mem_t, void* buf_v) -{ - uv_buf_t* buf_u = buf_v; - - size_t siz_t = uni_t * mem_t; - buf_u->base = c3_realloc(buf_u->base, 1 + siz_t + buf_u->len); - - memcpy(buf_u->base + buf_u->len, dat_v, siz_t); - buf_u->len += siz_t; - buf_u->base[buf_u->len] = 0; - - return siz_t; -} - /* _dawn_post_json(): POST JSON to url_c */ static uv_buf_t @@ -84,7 +66,7 @@ _dawn_post_json(c3_c* url_c, uv_buf_t lod_u) // u3K.ssl_curl_f(curl); curl_easy_setopt(curl, CURLOPT_URL, url_c); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _dawn_curl_alloc); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, king_curl_alloc); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&buf_u); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hed_u); @@ -131,7 +113,7 @@ _dawn_get_jam(c3_c* url_c) // u3K.ssl_curl_f(curl); curl_easy_setopt(curl, CURLOPT_URL, url_c); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _dawn_curl_alloc); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, king_curl_alloc); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&buf_u); result = curl_easy_perform(curl); diff --git a/pkg/vere/hamt_test.c b/pkg/vere/hamt_test.c new file mode 100644 index 0000000000..89c8c6c4ac --- /dev/null +++ b/pkg/vere/hamt_test.c @@ -0,0 +1,136 @@ +/// @file + +#include "noun.h" +#include "vere.h" +#include "ivory.h" +#include "ur.h" +// #include "pact.h" + + +// defined in noun/hashtable.c +c3_w _ch_skip_slot(c3_w mug_w, c3_w lef_w); + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + c3_d len_d = u3_Ivory_pill_len; + c3_y* byt_y = u3_Ivory_pill; + u3_cue_xeno* sil_u; + u3_weak pil; + + u3C.wag_w |= u3o_hashless; + u3m_boot_lite(1 << 26); + sil_u = u3s_cue_xeno_init_with(ur_fib27, ur_fib28); + if ( u3_none == (pil = u3s_cue_xeno_with(sil_u, len_d, byt_y)) ) { + printf("*** fail _setup 1\n"); + exit(1); + } + u3s_cue_xeno_done(sil_u); + if ( c3n == u3v_boot_lite(pil) ) { + printf("*** fail _setup 2\n"); + exit(1); + } +} + + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + // if ( !_test_safe() ) { + // fprintf(stderr, "test unix: failed\r\n"); + // exit(1); + // } + + u3p(u3h_root) pit_p = u3h_new_cache(1000000); + + u3_noun init = u3nc(u3i_string("mess"), + u3nc(48, + u3nc(c3__pact, + u3nc(13105, + u3nc(c3__etch, + u3nc(c3__init, + u3nc(u3i_string("chum"), + u3nc(49, + u3nc(u3i_string("~nec"), + u3nc(49, + u3nc(u3i_string("0voctt.mbs2p.q9qaf.b17em.tbsit.49vat.7ggc2.8avm6.oe870.fqhkt.dltit.u54hf.lse3l.au3pt"), 0) + ) + ) + )))))))); + u3h_put(pit_p, init, u3nc(c3y, u3_nul)); + u3z(init); + + for ( c3_w fra_w = 0; fra_w < 100000; fra_w++ ) { + u3_noun data = u3nc(u3i_string("mess"), + u3nc(48, + u3nc(c3__pact, + u3nc(13105, + u3nc(c3__etch, + u3nc(c3__data, + u3nc(u3dc("scot", c3__ud, fra_w), + u3nc(u3i_string("chum"), + u3nc(49, + u3nc(u3i_string("~nec"), + u3nc(49, + u3nc(u3i_string("0voctt.mbs2p.q9qaf.b17em.tbsit.49vat.7ggc2.8avm6.oe870.fqhkt.dltit.u54hf.lse3l.au3pt"), 0) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ); + + u3h_put(pit_p, data, u3nc(c3y, u3_nul)); + u3z(data); + } + + for ( c3_w fra_w = 0; fra_w < 100000; fra_w++ ) { + u3_noun data = u3nc(u3i_string("mess"), + u3nc(48, + u3nc(c3__pact, + u3nc(13105, + u3nc(c3__etch, + u3nc(c3__data, + u3nc(u3dc("scot", c3__ud, fra_w), + u3nc(u3i_string("chum"), + u3nc(49, + u3nc(u3i_string("~nec"), + u3nc(49, + u3nc(u3i_string("0voctt.mbs2p.q9qaf.b17em.tbsit.49vat.7ggc2.8avm6.oe870.fqhkt.dltit.u54hf.lse3l.au3pt"), 0) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ); + u3_weak res = u3h_git(pit_p, data); + if (res == u3_none) { + fprintf(stderr, "key gone from hamt %u: not ok\r\n", fra_w); + exit(1); + } + u3z(data); + } + + u3h_free(pit_p); + + u3m_grab(u3_none); + + fprintf(stderr, "test unix: ok\r\n"); + return 0; +} diff --git a/pkg/vere/io/ames.c b/pkg/vere/io/ames.c index 6d22d2eca1..27bd526625 100644 --- a/pkg/vere/io/ames.c +++ b/pkg/vere/io/ames.c @@ -777,7 +777,7 @@ _ames_send(u3_pact* pac_u) { uv_buf_t buf_u = uv_buf_init((c3_c*)pac_u->hun_y, pac_u->len_w); c3_i sas_i = uv_udp_send(&pac_u->snd_u, - &sam_u->wax_u, + &u3_Host.wax_u, &buf_u, 1, (const struct sockaddr*)&add_u, _ames_send_cb); @@ -1025,8 +1025,8 @@ _stun_send_cb(uv_udp_send_t *rep_u, c3_i sas_i) /* _stun_on_request(): hear stun request, send response. */ static void -_stun_on_request(u3_ames* sam_u, - const c3_y* req_y, +_stun_on_request(u3_ames* sam_u, + const c3_y* req_y, const struct sockaddr* adr_u) { _stun_send* snd_u = c3_malloc(sizeof(*snd_u) + 40); @@ -1039,7 +1039,7 @@ _stun_on_request(u3_ames* sam_u, u3_stun_make_response(req_y, &lan_u, snd_u->hun_y); uv_buf_t buf_u = uv_buf_init((c3_c*)snd_u->hun_y, 40); - c3_i sas_i = uv_udp_send(&snd_u->req_u, &sam_u->wax_u, + c3_i sas_i = uv_udp_send(&snd_u->req_u, &u3_Host.wax_u, &buf_u, 1, adr_u, _stun_send_cb); if ( sas_i ) { @@ -1116,7 +1116,7 @@ _stun_send_request(u3_ames* sam_u) add_u.sin_port = htons(sam_u->sun_u.lan_u.por_s); uv_buf_t buf_u = uv_buf_init((c3_c*)snd_u->hun_y, 28); - c3_i sas_i = uv_udp_send(&snd_u->req_u, &sam_u->wax_u, &buf_u, 1, + c3_i sas_i = uv_udp_send(&snd_u->req_u, &u3_Host.wax_u, &buf_u, 1, (const struct sockaddr*)&add_u, _stun_send_cb); if ( sas_i ) { @@ -2011,9 +2011,9 @@ _ames_try_forward(u3_pact* pac_u) ** trigger printfs suggesting upgrade. ** they cannot be filtered, as we do not know their semantics */ -static void +void _ames_hear(u3_ames* sam_u, - u3_lane* lan_u, + const struct sockaddr* adr_u, c3_w len_w, c3_y* hun_y) { @@ -2021,111 +2021,136 @@ _ames_hear(u3_ames* sam_u, c3_w pre_w; c3_w cur_w = 0; // cursor: how many bytes we've read from hun_y - // make sure packet is big enough to have a header - // - if ( HEAD_SIZE > len_w ) { - sam_u->sat_u.hed_d++; - if ( 0 == (sam_u->sat_u.hed_d % 100000) ) { - u3l_log("ames: %" PRIu64 " dropped, failed to read header", - sam_u->sat_u.hed_d); - } + // XX reorg, check if a STUN req/resp can look like an ames packet + // check the mug hash of the body of the packet, if not check if STUN + // otherwise , invalid packet, log failure + // check ames first, assume that STUN could maybe (not likely) overlap with ames + // for next protocol version, have an urbit cookie + // + if ( c3y == u3_stun_is_request(hun_y, len_w) ) { + _stun_on_request(sam_u, hun_y, adr_u); + c3_free(hun_y); + } + else if ( c3y == u3_stun_is_our_response(hun_y, + sam_u->sun_u.tid_y, len_w) ) + { + _stun_on_response(sam_u, hun_y, len_w); c3_free(hun_y); - return; } + else { + struct sockaddr_in* add_u = (struct sockaddr_in*)adr_u; + u3_lane lan_u = { + .por_s = ntohs(add_u->sin_port), + .pip_w = ntohl(add_u->sin_addr.s_addr) + }; - pac_u = c3_calloc(sizeof(*pac_u)); - pac_u->sam_u = sam_u; - pac_u->len_w = len_w; - pac_u->hun_y = hun_y; - pac_u->lan_u = *lan_u; - cur_w = 0; - - // parse the header - // - _ames_sift_head(&pac_u->hed_u, pac_u->hun_y); - cur_w += HEAD_SIZE; - - pac_u->typ_y = _ames_pact_typ(&pac_u->hed_u); + // make sure packet is big enough to have a header + // + if ( HEAD_SIZE > len_w ) { + sam_u->sat_u.hed_d++; + if ( 0 == (sam_u->sat_u.hed_d % 100000) ) { + u3l_log("ames: %" PRIu64 " dropped, failed to read header", + sam_u->sat_u.hed_d); + } - // ensure the protocol version matches ours - // - // XX rethink use of [fit_o] here and elsewhere - // - if ( (c3y == sam_u->fig_u.fit_o) - && (sam_u->ver_y != pac_u->hed_u.ver_y) ) - { - sam_u->sat_u.vet_d++; - if ( 0 == (sam_u->sat_u.vet_d % 100000) ) { - u3l_log("ames: %" PRIu64 " dropped for version mismatch", - sam_u->sat_u.vet_d); + c3_free(hun_y); + return; } - _ames_pact_free(pac_u); - return; - } - // check contents match mug in header - // - if ( c3n == _ames_check_mug(pac_u) ) { - // _log_head(&pac_u->hed_u); - sam_u->sat_u.mut_d++; - if ( 0 == (sam_u->sat_u.mut_d % 100000) ) { - u3l_log("ames: %" PRIu64 " dropped for invalid mug", - sam_u->sat_u.mut_d); - } - _ames_pact_free(pac_u); - return; - } + pac_u = c3_calloc(sizeof(*pac_u)); + pac_u->sam_u = sam_u; + pac_u->len_w = len_w; + pac_u->hun_y = hun_y; + pac_u->lan_u = lan_u; + cur_w = 0; - // check that packet is big enough for prelude - // - pre_w = _ames_prel_size(&pac_u->hed_u); - if ( len_w < cur_w + pre_w ) { - sam_u->sat_u.pre_d++; - if ( 0 == (sam_u->sat_u.pre_d % 100000) ) { - u3l_log("ames: %" PRIu64 " dropped, failed to read prelude", - sam_u->sat_u.pre_d); - } - _ames_pact_free(pac_u); - return; - } + // parse the header + // + _ames_sift_head(&pac_u->hed_u, pac_u->hun_y); + cur_w += HEAD_SIZE; - // parse prelude - // - _ames_sift_prel(&pac_u->hed_u, &pac_u->pre_u, pac_u->hun_y + cur_w); - cur_w += pre_w; + pac_u->typ_y = _ames_pact_typ(&pac_u->hed_u); - // if we can scry for lanes, - // and we are not the recipient, - // we might want to forward statelessly - // - if ( (c3y == sam_u->fig_u.see_o) - && ( (pac_u->pre_u.rec_d[0] != sam_u->pir_u->who_d[0]) - || (pac_u->pre_u.rec_d[1] != sam_u->pir_u->who_d[1]) ) ) - { - if ( c3y == sam_u->sat_u.for_o ) { - _ames_try_forward(pac_u); + // ensure the protocol version matches ours + // + // XX rethink use of [fit_o] here and elsewhere + // + if ( (c3y == sam_u->fig_u.fit_o) + && (sam_u->ver_y != pac_u->hed_u.ver_y) ) + { + sam_u->sat_u.vet_d++; + if ( 0 == (sam_u->sat_u.vet_d % 100000) ) { + u3l_log("ames: %" PRIu64 " dropped for version mismatch", + sam_u->sat_u.vet_d); + } + _ames_pact_free(pac_u); + return; } - } - else { - // enter protocol-specific packet handling + + // check contents match mug in header // - switch ( pac_u->typ_y ) { - case PACT_WAIL: { - _fine_hear_request(pac_u, cur_w); - } break; + if ( c3n == _ames_check_mug(pac_u) ) { + // _log_head(&pac_u->hed_u); + sam_u->sat_u.mut_d++; + if ( 0 == (sam_u->sat_u.mut_d % 100000) ) { + u3l_log("ames: %" PRIu64 " dropped for invalid mug", + sam_u->sat_u.mut_d); + } + _ames_pact_free(pac_u); + return; + } - case PACT_PURR: { - _fine_hear_response(pac_u, cur_w); - } break; + // check that packet is big enough for prelude + // + pre_w = _ames_prel_size(&pac_u->hed_u); + if ( len_w < cur_w + pre_w ) { + sam_u->sat_u.pre_d++; + if ( 0 == (sam_u->sat_u.pre_d % 100000) ) { + u3l_log("ames: %" PRIu64 " dropped, failed to read prelude", + sam_u->sat_u.pre_d); + } + _ames_pact_free(pac_u); + return; + } - case PACT_AMES: { - _ames_hear_ames(pac_u, cur_w); - } break; + // parse prelude + // + _ames_sift_prel(&pac_u->hed_u, &pac_u->pre_u, pac_u->hun_y + cur_w); + cur_w += pre_w; - default: { - u3l_log("ames_hear: bad packet type %d", pac_u->typ_y); - u3_pier_bail(u3_king_stub()); + // if we can scry for lanes, + // and we are not the recipient, + // we might want to forward statelessly + // + if ( (c3y == sam_u->fig_u.see_o) + && ( (pac_u->pre_u.rec_d[0] != sam_u->pir_u->who_d[0]) + || (pac_u->pre_u.rec_d[1] != sam_u->pir_u->who_d[1]) ) ) + { + if ( c3y == sam_u->sat_u.for_o ) { + _ames_try_forward(pac_u); + } + } + else { + // enter protocol-specific packet handling + // + switch ( pac_u->typ_y ) { + case PACT_WAIL: { + _fine_hear_request(pac_u, cur_w); + } break; + + case PACT_PURR: { + _fine_hear_response(pac_u, cur_w); + } break; + + case PACT_AMES: { + _ames_hear_ames(pac_u, cur_w); + } break; + + default: { + u3l_log("ames_hear: bad packet type %d", pac_u->typ_y); + u3_pier_bail(u3_king_stub()); + } } } } @@ -2140,7 +2165,7 @@ _ames_recv_cb(uv_udp_t* wax_u, const struct sockaddr* adr_u, unsigned flg_i) { - u3_ames* sam_u = wax_u->data; + u3_ames* sam_u = u3_Host.sam_u; // wax_u->data; if ( 0 > nrd_i ) { if ( u3C.wag_w & u3o_verbose ) { @@ -2157,32 +2182,10 @@ _ames_recv_cb(uv_udp_t* wax_u, } c3_free(buf_u->base); } - // XX reorg, check if a STUN req/resp can look like an ames packet - // check the mug hash of the body of the packet, if not check if STUN - // otherwise , invalid packet, log failure - // check ames first, assume that STUN could maybe (not likely) overlap with ames - // for next protocol version, have an urbit cookie - // - else if ( c3y == u3_stun_is_request((c3_y*)buf_u->base, nrd_i) ) { - _stun_on_request(sam_u, (c3_y *)buf_u->base, adr_u); - c3_free(buf_u->base); - } - else if ( c3y == u3_stun_is_our_response((c3_y*)buf_u->base, - sam_u->sun_u.tid_y, nrd_i) ) - { - _stun_on_response(sam_u, (c3_y*)buf_u->base, nrd_i); - c3_free(buf_u->base); - } else { - struct sockaddr_in* add_u = (struct sockaddr_in*)adr_u; - u3_lane lan_u = { - .por_s = ntohs(add_u->sin_port), - .pip_w = ntohl(add_u->sin_addr.s_addr) - }; - // NB: [nrd_i] will never exceed max length from _ames_alloc() // - _ames_hear(sam_u, &lan_u, (c3_w)nrd_i, (c3_y*)buf_u->base); + _ames_hear(sam_u, adr_u, (c3_w)nrd_i, (c3_y*)buf_u->base); } } @@ -2333,10 +2336,12 @@ _ames_io_start(u3_ames* sam_u) htonl(INADDR_ANY) : htonl(INADDR_LOOPBACK); add_u.sin_port = htons(por_s); + u3l_log("ames: skipping port: %u", por_s); - if ( (ret_i = uv_udp_bind(&sam_u->wax_u, + /*if ( (ret_i = uv_udp_bind(&sam_u->wax_u, (const struct sockaddr*)&add_u, 0)) != 0 ) { + u3l_log("ames: port: %u", por_s); u3l_log("ames: bind: %s", uv_strerror(ret_i)); if ( (c3y == zar_o) && @@ -2348,12 +2353,14 @@ _ames_io_start(u3_ames* sam_u) // XX revise // u3_pier_bail(u3_king_stub()); - } + }*/ + /* uv_udp_getsockname(&sam_u->wax_u, (struct sockaddr *)&add_u, &add_i); u3_assert(add_u.sin_port); sam_u->pir_u->por_s = ntohs(add_u.sin_port); + */ } if ( c3y == u3_Host.ops_u.net ) { @@ -2377,7 +2384,9 @@ _ames_io_start(u3_ames* sam_u) c3_free(our_s); } + /* uv_udp_recv_start(&sam_u->wax_u, _ames_alloc, _ames_recv_cb); + */ sam_u->car_u.liv_o = c3y; u3z(who); @@ -2608,16 +2617,16 @@ _ames_io_talk(u3_auto* car_u) // send born event // - { - // XX remove [sev_l] - // - u3_noun wir = u3nt(c3__newt, - u3dc("scot", c3__uv, sam_u->sev_l), - u3_nul); - u3_noun cad = u3nc(c3__born, u3_nul); + // { + // // XX remove [sev_l] + // // + // u3_noun wir = u3nt(c3__newt, + // u3dc("scot", c3__uv, sam_u->sev_l), + // u3_nul); + // u3_noun cad = u3nc(c3__born, u3_nul); - u3_auto_plan(car_u, u3_ovum_init(0, c3__a, wir, cad)); - } + // u3_auto_plan(car_u, u3_ovum_init(0, c3__a, wir, cad)); + // } // scry the protocol version out of arvo // @@ -2626,6 +2635,8 @@ _ames_io_talk(u3_auto* car_u) // (or some other reconfig) effect when it is reset. // u3_noun gang = u3nc(u3_nul, u3_nul); + // XX drop this; done at another level + // u3_pier_peek_last(car_u->pir_u, gang, c3__ax, u3_nul, u3nt(u3i_string("protocol"), u3i_string("version"), u3_nul), sam_u, _ames_prot_scry_cb); @@ -2633,7 +2644,7 @@ _ames_io_talk(u3_auto* car_u) /* _ames_kick_newt(): apply packet network outputs. */ -static c3_o +c3_o _ames_kick_newt(u3_ames* sam_u, u3_noun tag, u3_noun dat) { c3_o ret_o; @@ -2667,6 +2678,7 @@ _ames_kick_newt(u3_ames* sam_u, u3_noun tag, u3_noun dat) sam_u->nal_o = c3y; ret_o = c3y; } break; + } u3z(tag); u3z(dat); @@ -2903,6 +2915,7 @@ u3_ames_io_init(u3_pier* pir_u) sam_u->lax_p = u3h_new_cache(500000); u3_assert( !uv_udp_init(u3L, &sam_u->wax_u) ); + uv_udp_init(u3L, &u3_Host.wax_u); sam_u->wax_u.data = sam_u; sam_u->sil_u = u3s_cue_xeno_init(); @@ -2935,5 +2948,7 @@ u3_ames_io_init(u3_pier* pir_u) u3z(now); } + // XX declare void pointer to u3_host and add sam_u in it + u3_Host.sam_u = sam_u; return car_u; } diff --git a/pkg/vere/io/ames/stun.c b/pkg/vere/io/ames/stun.c index 8bdad69742..0f830c1f4a 100644 --- a/pkg/vere/io/ames/stun.c +++ b/pkg/vere/io/ames/stun.c @@ -21,10 +21,10 @@ _stun_add_fingerprint(c3_y *message, c3_w index) } static c3_o -_stun_has_fingerprint(c3_y* buf_y, c3_w len_w) +_stun_has_fingerprint(c3_y* buf_y, c3_w buf_len_w) { c3_y ned_y[4] = {0x80, 0x28, 0x00, 0x04}; - if ( len_w < 28 ) { // At least STUN header and FINGERPRINT + if ( buf_len_w < 28 ) { // At least STUN header and FINGERPRINT return c3n; } @@ -32,14 +32,14 @@ _stun_has_fingerprint(c3_y* buf_y, c3_w len_w) c3_y* fin_y = 0; c3_w i = 20; // start after the header - fin_y = memmem(buf_y + i, len_w - i, ned_y, sizeof(ned_y)); + fin_y = memmem(buf_y + i, buf_len_w - i, ned_y, sizeof(ned_y)); if ( fin_y != 0 ) { c3_w lin_w = fin_y - buf_y; // Skip attribute type and length c3_w fingerprint = c3_sift_word(fin_y + sizeof(ned_y)); c3_w init = crc32(0L, Z_NULL, 0); c3_w crc = htonl(crc32(init, buf_y, lin_w) ^ 0x5354554e); - if ((fingerprint == crc) && (fin_y - buf_y + 8) == len_w) { + if ((fingerprint == crc) && (fin_y - buf_y + 8) == buf_len_w) { return c3y; } } @@ -128,6 +128,9 @@ u3_stun_make_response(const c3_y req_y[20], buf_y[0] = 0x01; buf_y[1] = 0x01; // 0x0101 SUCCESS RESPONSE buf_y[2] = 0x00; buf_y[3] = 0x14; // Length: 20 bytes + buf_y[0] = 0x01; buf_y[1] = 0x01; // 0x0101 SUCCESS RESPONSE + buf_y[2] = 0x00; buf_y[3] = 0x14; // Length: 20 bytes + memset(buf_y + cur_w, 0, cur_w); // XOR-MAPPED-ADDRESS diff --git a/pkg/vere/io/http.c b/pkg/vere/io/http.c index 63812a4792..094c813af6 100644 --- a/pkg/vere/io/http.c +++ b/pkg/vere/io/http.c @@ -44,7 +44,8 @@ typedef struct _u3_h2o_serv { typedef struct _u3_preq { struct _u3_hreq* req_u; // originating request (nullable) struct _u3_httd* htd_u; // device backpointer - u3_noun pax; // partial scry path + u3_noun pax; // partial scry path + c3_o las_o; // was scry at now } u3_preq; /* u3_hcon: incoming http connection. @@ -638,7 +639,235 @@ _http_seq_new(u3_hcon* hon_u, h2o_req_t* rec_u) return req_u; } -/* _http_req_dispatch(): dispatch http request to %eyre +static void +_http_cache_respond(u3_hreq* req_u, u3_noun nun); + +static void +_http_scry_respond(u3_hreq* req_u, u3_noun nun); + +typedef struct _byte_range { + c3_z beg_z; + c3_z end_z; +} byte_range; + +/* _chunk_align(): align range to a nearby chunk +*/ +static void +_chunk_align(byte_range* rng_u) +{ + c3_z siz_z = 4194304; // 4MiB + + if ( SIZE_MAX != rng_u->beg_z ) { + if ( rng_u->beg_z > rng_u->end_z ) { + rng_u->beg_z = SIZE_MAX; + rng_u->end_z = SIZE_MAX; + } + else { + // XX an out-of-bounds request could be aligned to in-bounds + // resulting in a 200 or 206 response instead of 416. + // browsers should have the total length from content-range, + // and send reasonable range requests. + // + rng_u->beg_z = (rng_u->beg_z / siz_z) * siz_z; + rng_u->end_z = (rng_u->beg_z + siz_z) - 1; + } + } + else if ( SIZE_MAX != rng_u->end_z ) { + // round up to multiple of siz_z + rng_u->end_z = siz_z * ((rng_u->end_z / siz_z) + 1); + } +} + +/* _parse_range(): get a range from '-' delimited text +*/ +static byte_range +_parse_range(c3_c* txt_c, c3_w len_w) +{ + c3_c* hep_c = memchr(txt_c, '-', len_w); + byte_range rng_u; + rng_u.beg_z = SIZE_MAX; + rng_u.end_z = SIZE_MAX; + + if ( hep_c ) { + rng_u.beg_z = h2o_strtosize(txt_c, hep_c - txt_c); + rng_u.end_z = h2o_strtosize(hep_c + 1, len_w - ((hep_c + 1) - txt_c)); + // strange -> [SIZE_MAX SIZE_MAX] + if ( ((SIZE_MAX == rng_u.beg_z) && (hep_c != txt_c)) + || ((SIZE_MAX == rng_u.end_z) && (len_w - ((hep_c + 1) - txt_c) > 0)) + || ((SIZE_MAX != rng_u.beg_z) && (rng_u.beg_z > rng_u.end_z)) ) + { + rng_u.beg_z = SIZE_MAX; + rng_u.end_z = SIZE_MAX; + } + } + return rng_u; +} + +/* _get_range(): get a _byte_range from headers +*/ +static c3_o +_get_range(h2o_headers_t req_headers, byte_range* rng_u) +{ + rng_u->beg_z = SIZE_MAX; + rng_u->end_z = SIZE_MAX; + + c3_w inx_w = h2o_find_header(&req_headers, H2O_TOKEN_RANGE, -1); + if ( UINT32_MAX == inx_w) { + return c3n; + } + + if ( (req_headers.entries[inx_w].value.len >= 6) + && (0 == memcmp("bytes=", req_headers.entries[inx_w].value.base, 6)) ) + { + byte_range tmp_u = _parse_range(req_headers.entries[inx_w].value.base + 6, + req_headers.entries[inx_w].value.len - 6); + rng_u->beg_z = tmp_u.beg_z; + rng_u->end_z = tmp_u.end_z; + } + + return c3y; +} + +/* _http_scry_cb(): respond and maybe cache scry result +*/ +static void +_http_scry_cb(void* vod_p, u3_noun nun) +{ + u3_preq* peq_u = vod_p; + u3_httd* htd_u = peq_u->htd_u; + u3_hreq* req_u = peq_u->req_u; + u3_hfig* fig_u = &req_u->hon_u->htp_u->htd_u->fig_u; + c3_o auth = _http_req_is_auth(fig_u, req_u->rec_u); + + if ( req_u ) { + u3_assert(u3_rsat_peek == req_u->sat_e); + req_u->peq_u = 0; + _http_scry_respond(req_u, u3k(nun)); + } + + // cache only if peek was not at now, and nun isn't u3_nul + if ( (c3n == peq_u->las_o) + && (u3_nul != nun) ) + { + u3_noun key = u3nc(auth, u3k(peq_u->pax)); + u3h_put(htd_u->nax_p, key, nun); + u3z(key); + } + else { + u3z(nun); + } + + u3z(peq_u->pax); + c3_free(peq_u); +} + +/* _beam: ship desk case spur +*/ +typedef struct _beam { + u3_weak who; + u3_weak des; + u3_weak cas; + u3_weak pur; +} beam; + +/* _free_beam(): free a beam +*/ +static void +_free_beam(beam* bem) +{ + u3z(bem->who); + u3z(bem->des); + u3z(bem->cas); + u3z(bem->pur); +} + +/* _get_beam(): get a _beam from url +*/ +static beam +_get_beam(u3_hreq* req_u, c3_c* txt_c, c3_w len_w) +{ + beam bem; + + // get beak + // + for ( c3_w i_w = 0; i_w < 3; ++i_w ) { + u3_noun* wer; + if ( 0 == i_w ) { + wer = &bem.who; + } + else if ( 1 == i_w ) { + wer = &bem.des; + } + else { + wer = &bem.cas; + } + + // find '//' + if ( (len_w >= 2) + && ('/' == txt_c[0]) + && ('/' == txt_c[1]) ) + { + *wer = u3_nul; + txt_c++; + len_w--; + } + // skip '/' + else if ( (len_w > 0) && ('/' == txt_c[0]) ) { + txt_c++; + len_w--; + } + + // '=' + if ( (len_w > 0) && ('=' == txt_c[0]) ) { + if ( 0 == i_w ) { + u3_http* htp_u = req_u->hon_u->htp_u; + u3_httd* htd_u = htp_u->htd_u; + *wer = u3dc("scot", 'p', u3i_chubs(2, htd_u->car_u.pir_u->who_d)); + } + else if ( 1 == i_w ) { + *wer = c3__base; + } + else { + req_u->peq_u->las_o = c3y; + } + txt_c++; + len_w--; + } + // slice cord + else { + c3_c* nex_c; + c3_c* tis_c = memchr(txt_c, '=', len_w); + c3_c* fas_c = memchr(txt_c, '/', len_w); + + if ( tis_c && fas_c ) { + nex_c = c3_min(tis_c, fas_c); + } + else { + nex_c = ( tis_c ) ? tis_c : fas_c; + } + + if ( !nex_c ) { + *wer = u3_none; + return bem; + } + else { + c3_w dif_w = (c3_p)(nex_c - txt_c); + *wer = u3i_bytes(dif_w, (const c3_y*)txt_c); + txt_c = nex_c; + len_w = len_w - dif_w; + } + } + } + + // get spur + u3_noun tmp = u3dc("rush", u3i_bytes(len_w, (const c3_y*)txt_c), u3v_wish("stap")); + bem.pur = ( u3_nul == tmp ) ? u3_none : u3k(u3t(tmp)); + u3z(tmp); + + return bem; +} + +/* _http_req_dispatch(): dispatch http request */ static void _http_req_dispatch(u3_hreq* req_u, u3_noun req) @@ -649,28 +878,137 @@ _http_req_dispatch(u3_hreq* req_u, u3_noun req) { u3_http* htp_u = req_u->hon_u->htp_u; u3_httd* htd_u = htp_u->htd_u; - u3_noun wir = _http_req_to_duct(req_u); - u3_noun cad; + c3_c* bas_c = req_u->rec_u->input.path.base; + c3_w len_w = req_u->rec_u->input.path.len; + + // check if base url starts with '/_~_/' + if ( (len_w < 6) + || (0 != memcmp("/_~_/", bas_c, 5)) ) { + // no: inject to arvo + u3_noun wir = _http_req_to_duct(req_u); + u3_noun cad; u3_noun adr = u3nc(c3__ipv4, u3i_words(1, &req_u->hon_u->ipf_w)); // XX loopback automatically secure too? - // + // u3_noun dat = u3nt(htp_u->sec, adr, req); cad = ( c3y == req_u->hon_u->htp_u->lop ) ? u3nc(u3i_string("request-local"), dat) : u3nc(u3i_string("request"), dat); + u3_auto_plan(&htd_u->car_u, u3_ovum_init(0, c3__e, wir, cad)); } + else { + // '/_~_/' found + bas_c = bas_c + 4; // retain '/' after /_~_ + len_w = len_w - 4; + + req_u->peq_u = c3_malloc(sizeof(*req_u->peq_u)); + req_u->peq_u->req_u = req_u; + req_u->peq_u->htd_u = htd_u; + req_u->peq_u->las_o = c3n; + req_u->sat_e = u3_rsat_peek; + req_u->peq_u->pax = u3_nul; + + u3_hfig* fig_u = &req_u->hon_u->htp_u->htd_u->fig_u; + h2o_req_t* rec_u = req_u->rec_u; + + // set gang to [~ ~] or ~ + u3_noun gang; + c3_o auth = _http_req_is_auth(fig_u, rec_u); + if ( auth == c3y ) { + gang = u3nc(u3_nul, u3_nul); + } + else { + gang = u3_nul; + } - u3_auto_plan(&htd_u->car_u, u3_ovum_init(0, c3__e, wir, cad)); + beam bem = _get_beam(req_u, bas_c, len_w); + if ( (u3_none == bem.who) + || (u3_none == bem.des) + || (u3_none == bem.cas) + || (u3_none == bem.pur) ) + { + c3_c* msg_c = "bad request"; + h2o_send_error_generic(req_u->rec_u, 400, msg_c, msg_c, 0); + u3z(gang); + u3z(req_u->peq_u->pax); + _free_beam(&bem); + return; + } + + h2o_headers_t req_headers = req_u->rec_u->headers; + byte_range rng_u; + c3_o rng_o = _get_range(req_headers, &rng_u); + + // prepare spur for eyre range scry + // + u3_noun spur; + if ( c3n == rng_o ) { + // full range: '/range/0//foo' + spur = u3nq(u3i_string("range"), c3_s1('0'), u3_blip, u3k(bem.pur)); + } + else { + _chunk_align(&rng_u); + + u3_atom beg = ( SIZE_MAX == rng_u.beg_z) ? + u3_blip : u3dc("scot", c3__ud, u3i_chub(rng_u.beg_z)); + u3_atom end = ( SIZE_MAX == rng_u.end_z) ? + u3_blip : u3dc("scot", c3__ud, u3i_chub(rng_u.end_z)); + + spur = u3nq(u3i_string("range"), beg, end, u3k(bem.pur)); + } + + // peek or respond from cache + // + if ( c3y == req_u->peq_u->las_o ) { + u3_noun our = u3dc("scot", 'p', u3i_chubs(2, htd_u->car_u.pir_u->who_d)); + if ( our == bem.who ) { + u3_pier_peek_last(htd_u->car_u.pir_u, gang, c3__ex, + u3k(bem.des), spur, req_u->peq_u, _http_scry_cb); + } + else { + c3_c* msg_c = "bad request"; + h2o_send_error_generic(req_u->rec_u, 400, msg_c, msg_c, 0); + u3z(gang); + u3z(spur); + u3z(req_u->peq_u->pax); + } + u3z(our); + } + else { + u3_noun bam = u3nq(u3k(bem.who), u3k(bem.des), u3k(bem.cas), spur); + u3_noun key = u3nc(auth, u3k(bam)); + u3_weak nac = u3h_get(htd_u->nax_p, key); + u3z(key); + + if ( (u3_none == nac) + || ((u3_nul == gang) && (c3y == u3r_at(14, nac))) ) + { + // maybe cache, then serve subsequent range requests from cache + u3z(req_u->peq_u->pax); + req_u->peq_u->pax = u3k(bam); + u3_pier_peek(htd_u->car_u.pir_u, gang, u3nt(0, c3__ex, bam), + req_u->peq_u, _http_scry_cb); + u3z(nac); + } + else { + _http_scry_respond(req_u, nac); + u3z(bam); + u3z(gang); + } + } + _free_beam(&bem); + } } } /* _http_cache_respond(): respond with a simple-payload:http */ static void -_http_cache_respond(u3_hreq* req_u, u3_noun nun) { +_http_cache_respond(u3_hreq* req_u, u3_noun nun) +{ h2o_req_t* rec_u = req_u->rec_u; u3_httd* htd_u = req_u->hon_u->htp_u->htd_u; @@ -694,7 +1032,52 @@ _http_cache_respond(u3_hreq* req_u, u3_noun nun) { } else { u3_noun auth, response_header, data; - u3x_qual(u3k(u3t(u3t(nun))), &auth, 0, &response_header, &data); + u3x_qual(u3t(u3t(nun)), &auth, 0, &response_header, &data); + u3_noun status, headers; + u3x_cell(response_header, &status, &headers); + + // check auth + if ( (c3y == auth) + && (c3n == _http_req_is_auth(&htd_u->fig_u, rec_u)) ) + { + h2o_send_error_403(rec_u, "Unauthorized", "unauthorized", 0); + } + else { + req_u->sat_e = u3_rsat_plan; + _http_start_respond(req_u, u3k(status), u3k(headers), u3k(data), c3y); + } + } + u3z(nun); +} + +/* _http_scry_respond(): respond with a simple-payload:http +*/ +static void +_http_scry_respond(u3_hreq* req_u, u3_noun nun) +{ + h2o_req_t* rec_u = req_u->rec_u; + u3_httd* htd_u = req_u->hon_u->htp_u->htd_u; + + if ( u3_nul == nun ) { + u3_weak req = _http_rec_to_httq(rec_u); + if ( u3_none == req ) { + if ( (u3C.wag_w & u3o_verbose) ) { + u3l_log("strange %.*s request", (c3_i)rec_u->method.len, + rec_u->method.base); + } + c3_c* msg_c = "bad request"; + h2o_send_error_generic(rec_u, 400, msg_c, msg_c, 0); + } + else { + h2o_send_error_500(rec_u, "Internal Server Error", "scry failed", 0); + } + } + else if ( u3_none == u3r_at(7, nun) ) { + h2o_send_error_500(rec_u, "Internal Server Error", "scry failed", 0); + } + else { + u3_noun auth, response_header, data; + u3x_qual(u3t(u3t(nun)), &auth, 0, &response_header, &data); u3_noun status, headers; u3x_cell(response_header, &status, &headers); diff --git a/pkg/vere/io/lss.c b/pkg/vere/io/lss.c new file mode 100644 index 0000000000..c492730f6e --- /dev/null +++ b/pkg/vere/io/lss.c @@ -0,0 +1,393 @@ +/// @file + +#include "vere.h" +#include +#include +#include "urcrypt.h" +#include "lss.h" + +static c3_y IV[32] = {103, 230, 9, 106, 133, 174, 103, 187, 114, 243, 110, 60, 58, 245, 79, 165, 127, 82, 14, 81, 140, 104, 5, 155, 171, 217, 131, 31, 25, 205, 224, 91}; + +static void _leaf_hash(lss_hash out, c3_y* leaf_y, c3_w leaf_w, c3_d counter_d) +{ + c3_y cv[32]; + memcpy(cv, IV, 32); + c3_y block[64] = {0}; + c3_y block_len = 0; + c3_y flags = 0; + urcrypt_blake3_chunk_output(leaf_w, leaf_y, cv, block, &block_len, &counter_d, &flags); + urcrypt_blake3_compress(cv, block, block_len, counter_d, flags, block); + memcpy(out, block, 32); +} + +static void _parent_hash(lss_hash out, lss_hash left, lss_hash right) +{ + c3_y cv[32]; + memcpy(cv, IV, 32); + c3_y block[64]; + memcpy(block, left, 32); + memcpy(block + 32, right, 32); + c3_y block_len = 64; + c3_y flags = 1 << 2; // PARENT + urcrypt_blake3_compress(cv, block, block_len, 0, flags, block); + memcpy(out, block, 32); +} + +static void _subtree_root(lss_hash out, c3_y* leaf_y, c3_w leaf_w, c3_d counter_d) +{ + if ( leaf_w <= 1024 ) { + _leaf_hash(out, leaf_y, leaf_w, counter_d); + return; + } + c3_w leaves_w = (leaf_w + 1023) / 1024; + c3_w mid_w = 1 << (c3_bits_word(leaves_w-1) - 1); + lss_hash l, r; + _subtree_root(l, leaf_y, (mid_w * 1024), counter_d); + _subtree_root(r, leaf_y + (mid_w * 1024), leaf_w - (mid_w * 1024), counter_d + mid_w); + _parent_hash(out, l, r); +} + +c3_w lss_proof_size(c3_w leaves) { + return 1 + c3_bits_word(leaves-1); +} + +c3_o _lss_expect_pair(c3_w leaves, c3_w i) { + return __((i != 0) && ((i + (1 << (1+c3_tz_w(i)))) < leaves)); +} + +static void _lss_builder_merge(lss_builder* bil_u, c3_w height, lss_hash l, lss_hash r) { + // whenever two subtrees are merged, insert them into the pairs array; + // if the merged tree is part of the left-side "spine" of the tree, + // instead add the right subtree to the initial proof + if ( bil_u->counter >> (height+1) ) { + c3_w i = (bil_u->counter&~((1<<(height+1))-1)) - (1<pairs[i][0], l, sizeof(lss_hash)); + memcpy(bil_u->pairs[i][1], r, sizeof(lss_hash)); + } else { + if (height == 0) { + memcpy(bil_u->proof[0], l, sizeof(lss_hash)); // proof always begins with [0, 1) + } + memcpy(bil_u->proof[height+1], r, sizeof(lss_hash)); + } +} + +void lss_builder_ingest(lss_builder* bil_u, c3_y* leaf_y, c3_w leaf_w) { + lss_hash h; + _leaf_hash(h, leaf_y, leaf_w, bil_u->counter); + c3_w height = 0; + while ( bil_u->counter&(1<trees[height], h); + _parent_hash(h, bil_u->trees[height], h); + height++; + } + memcpy(bil_u->trees[height], h, sizeof(lss_hash)); + bil_u->counter++; +} + +c3_w lss_builder_transceive(lss_builder* bil_u, c3_w steps, c3_y* jumbo_y, c3_w jumbo_w, lss_pair* pair) { + if ( pair != NULL ) { + c3_w i = bil_u->counter; + memcpy(bil_u->pairs[i][0], (*pair)[0], sizeof(lss_hash)); + memcpy(bil_u->pairs[i][1], (*pair)[1], sizeof(lss_hash)); + } + for (c3_w i = 0; (i < (1< 0); i++) { + c3_w leaf_w = c3_min(jumbo_w, 1024); + lss_builder_ingest(bil_u, jumbo_y, leaf_w); + jumbo_y += leaf_w; + jumbo_w -= leaf_w; + } + return c3_min(bil_u->counter - (1<leaves); +} + +lss_hash* lss_builder_finalize(lss_builder* bil_u) { + if ( bil_u->counter != 0 ) { + c3_w height = c3_tz_w(bil_u->counter); + lss_hash h; + memcpy(h, bil_u->trees[height], sizeof(lss_hash)); + for (height++; height < sizeof(bil_u->trees)/sizeof(lss_hash); height++) { + if ( bil_u->counter&(1<trees[height], h); + _parent_hash(h, bil_u->trees[height], h); + } + } + } + return bil_u->proof; +} + +lss_pair* lss_builder_pair(lss_builder* bil_u, c3_w i) { + if ( c3y == _lss_expect_pair(bil_u->leaves, i) ) { + return &bil_u->pairs[i]; + } + return NULL; +} + +void lss_builder_init(lss_builder* bil_u, c3_w leaves) { + bil_u->leaves = leaves; + bil_u->counter = 0; + bil_u->proof = c3_calloc(lss_proof_size(leaves) * sizeof(lss_hash)); + bil_u->pairs = c3_calloc(leaves * sizeof(lss_pair)); +} + +void lss_builder_free(lss_builder* bil_u) { + c3_free(bil_u->proof); + c3_free(bil_u->pairs); + c3_free(bil_u); +} + +lss_hash* lss_transceive_proof(lss_hash* proof, c3_w steps) { + for (c3_w i = 0; i < steps; i++) { + _parent_hash(proof[i+1], proof[i], proof[i+1]); + } + return proof + steps; +} + +static c3_o _lss_verifier_check_hash(lss_verifier* los_u, c3_w i, c3_w height, lss_hash h) +{ + // Binary numeral trees are composed of a set of perfect binary trees of + // unique heights. Unless the set consists of a single tree, there will be + // pairs that span two trees. We call these pairs "odd" because the heights of + // their children are uneven. Specifically, the left child of an odd pair has + // a greater height than the right child. + // + // When such a pair is inserted by lss_verifier_ingest, both children are + // inserted at the same height, causing right child to be in the "wrong" + // place. The abstruse bithacking below corrects for this. First, it + // calculates the positions of the odd pairs within a tree of this size. Then + // it determines how many odd pairs are directly above us, and increments the + // height accordingly. A mask is used to ensure that we only perform this + // adjustment when necessary. + c3_w odd = (1<leaves-1)) - los_u->leaves; + c3_w mask = (1<leaves-1))) - 1; + height += c3_tz_w(~((odd&~mask) >> height)); + c3_b parity = (i >> height) & 1; + return __(memcmp(los_u->pairs[height][parity], h, sizeof(lss_hash)) == 0); +} + +c3_o lss_verifier_ingest(lss_verifier* los_u, c3_y* leaf_y, c3_w leaf_w, lss_pair* pair) { + // verify leaf + lss_hash h; + _subtree_root(h, leaf_y, leaf_w, los_u->counter << los_u->steps); + if ( c3n == _lss_verifier_check_hash(los_u, los_u->counter, 0, h) ) { + return c3n; + } + // check whether pair is expected + if ( (pair != NULL) != (c3y == _lss_expect_pair(los_u->leaves, los_u->counter)) ) { + return c3n; + } else if (pair == NULL) { + los_u->counter++; + return c3y; + } + // verify and insert pair + c3_w height = c3_tz_w(los_u->counter); + c3_w start = los_u->counter + (1 << height); // first leaf "covered" by this pair + lss_hash parent_hash; + _parent_hash(parent_hash, (*pair)[0], (*pair)[1]); + if ( c3n == _lss_verifier_check_hash(los_u, start, height+1, parent_hash) ) { + return c3n; + } + memcpy(los_u->pairs[height][0], (*pair)[0], sizeof(lss_hash)); + memcpy(los_u->pairs[height][1], (*pair)[1], sizeof(lss_hash)); + los_u->counter++; + return c3y; +} + +void lss_verifier_init(lss_verifier* los_u, c3_w steps, c3_w leaves, lss_hash* proof) { + c3_w proof_w = lss_proof_size(leaves); + c3_w pairs_w = c3_bits_word(leaves); + los_u->steps = steps; + los_u->leaves = leaves; + los_u->counter = 0; + los_u->pairs = c3_calloc(pairs_w * sizeof(lss_pair)); + memcpy(los_u->pairs[0][0], proof[0], sizeof(lss_hash)); + for (c3_w i = 1; i < proof_w; i++) { + memcpy(los_u->pairs[i-1][1], proof[i], sizeof(lss_hash)); + } +} + +void lss_verifier_free(lss_verifier* los_u) { + c3_free(los_u->pairs); + c3_free(los_u); +} + +void lss_complete_inline_proof(lss_hash* proof, c3_y* leaf_y, c3_w leaf_w) { + _subtree_root(proof[0], leaf_y, leaf_w, 0); +} + +void lss_root(lss_hash root, lss_hash* proof, c3_w proof_w) { + memcpy(root, proof[0], sizeof(lss_hash)); + for (c3_w i = 1; i < proof_w; i++) { + _parent_hash(root, root, proof[i]); + } +} + +#ifdef LSS_TEST + +static lss_pair* _make_pair(lss_hash left, lss_hash right) +{ + lss_pair* pair = c3_malloc(sizeof(lss_pair)); + memcpy((*pair)[0], left, 32); + memcpy((*pair)[1], right, 32); + return pair; +} + +static void _test_lss_manual_verify_8() +{ + #define asrt_ok(y) if ( c3y != y ) { fprintf(stderr, "failed at %s:%u\n", __FILE__, __LINE__); exit(1); } + + c3_w dat_w = 1024 * 7 + 1; + c3_y* dat_y = c3_calloc(dat_w); + + c3_y* leaves_y[8]; + c3_w leaves_w[8]; + lss_hash leaves_h[8]; + lss_pair *pairs[8]; + + // construct leaves + for ( c3_w i = 0; i < 8; i++ ) { + leaves_y[i] = dat_y + 1024 * i; + leaves_w[i] = i < 7 ? 1024 : 1; + _leaf_hash(leaves_h[i], leaves_y[i], leaves_w[i], i); + pairs[i] = NULL; + } + // construct pairs + pairs[1] = _make_pair(leaves_h[2], leaves_h[3]); + pairs[3] = _make_pair(leaves_h[4], leaves_h[5]); + pairs[5] = _make_pair(leaves_h[6], leaves_h[7]); + lss_hash pair3_hash; + _parent_hash(pair3_hash, (*pairs[3])[0], (*pairs[3])[1]); + lss_hash pair5_hash; + _parent_hash(pair5_hash, (*pairs[5])[0], (*pairs[5])[1]); + pairs[2] = _make_pair(pair3_hash, pair5_hash); + + // construct proof + lss_hash *proof = c3_calloc(4 * sizeof(lss_hash)); + memcpy(proof[0], leaves_h[0], 32); + memcpy(proof[1], leaves_h[1], 32); + _parent_hash(proof[2], leaves_h[2], leaves_h[3]); + _parent_hash(proof[3], (*pairs[2])[0], (*pairs[2])[1]); + + // verify + lss_verifier lss_u; + memset(&lss_u, 0, sizeof(lss_verifier)); + lss_verifier_init(&lss_u, 0, 8, proof); + for ( c3_w i = 0; i < 8; i++ ) { + asrt_ok(lss_verifier_ingest(&lss_u, leaves_y[i], leaves_w[i], pairs[i])) + } + + #undef asrt_ok +} + +static void _test_lss_build_verify(c3_w dat_w) +{ + #define asrt_ok(y) if ( c3y != y ) { fprintf(stderr, "failed at %s:%u\n", __FILE__, __LINE__); exit(1); } + + c3_y* dat_y = c3_calloc(dat_w); + for ( c3_w i = 0; i < dat_w; i++ ) { + dat_y[i] = i; + } + c3_w leaves_w = (dat_w + 1023) / 1024; + + // build + lss_builder bil_u; + lss_builder_init(&bil_u, leaves_w); + for ( c3_w i = 0; i < leaves_w; i++ ) { + c3_y* leaf_y = dat_y + (i*1024); + c3_w leaf_w = (i < leaves_w - 1) ? 1024 : dat_w % 1024; + lss_builder_ingest(&bil_u, leaf_y, leaf_w); + } + lss_hash* proof = lss_builder_finalize(&bil_u); + + // verify + lss_verifier lss_u; + lss_verifier_init(&lss_u, 0, leaves_w, proof); + for ( c3_w i = 0; i < leaves_w; i++ ) { + c3_y* leaf_y = dat_y + (i*1024); + c3_w leaf_w = (i < leaves_w - 1) ? 1024 : dat_w % 1024; + lss_pair* pair = lss_builder_pair(&bil_u, i); + asrt_ok(lss_verifier_ingest(&lss_u, leaf_y, leaf_w, pair)); + } + + #undef asrt_ok +} + +static void _test_lss_build_verify_jumbo(c3_w steps, c3_w dat_w) +{ + #define asrt_ok(y) if ( c3y != y ) { fprintf(stderr, "failed at %s:%u\n", __FILE__, __LINE__); exit(1); } + + c3_y* dat_y = c3_calloc(dat_w); + for ( c3_w i = 0; i < dat_w; i++ ) { + dat_y[i] = i; + } + c3_w leaves_w = (dat_w + 1023) / 1024; + + // build + lss_builder bil_u; + lss_builder_init(&bil_u, leaves_w); + for ( c3_w i = 0; i < leaves_w; i++ ) { + c3_y* leaf_y = dat_y + (i*1024); + c3_w leaf_w = c3_min(dat_w - (i*1024), 1024); + lss_builder_ingest(&bil_u, leaf_y, leaf_w); + } + lss_hash* proof = lss_builder_finalize(&bil_u); + + // transceive up + c3_w jumbo_leaf_w = 1024 << steps; + c3_w jumbo_leaves_w = (dat_w + jumbo_leaf_w - 1) / jumbo_leaf_w; + + // verify (if possible) + if ( jumbo_leaves_w > 1 ) { + lss_verifier lss_u; + lss_verifier_init(&lss_u, steps, jumbo_leaves_w, lss_transceive_proof(proof, steps)); + for ( c3_w i = 0; i < jumbo_leaves_w; i++ ) { + c3_y* leaf_y = dat_y + (i*(1024< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lss.h" + +c3_o dop_o = c3n; + +#define MESA_DEBUG c3y +//#define MESA_TEST +#define RED_TEXT "\033[0;31m" +#define DEF_TEXT "\033[0m" +#define REORDER_THRESH 5 + +#define DIRECT_ROUTE_TIMEOUT_MICROS 5000000 +#define DIRECT_ROUTE_RETRY_MICROS 1000000 + +// logging and debug symbols +#define MESA_SYM_DESC(SYM) MESA_DESC_ ## SYM +#define MESA_SYM_FIELD(SYM) MESA_FIELD_ ## SYM +#ifdef MESA_DEBUG + #define MESA_LOG(SAM_U, SYM, ...) { SAM_U->sat_u.MESA_SYM_FIELD(SYM)++; u3l_log("mesa: (%u) %s", __LINE__, MESA_SYM_DESC(SYM)); } +#else + #define MESA_LOG(SAM_U, SYM, ...) { SAM_U->sat_u.MESA_SYM_FIELD(SYM)++; } +#endif + +typedef struct _u3_mesa_stat { + c3_w dop_w; // dropped for other reasons + c3_w ser_w; // dropped for serialisation + c3_w aut_w; // droppped for auth + c3_w apa_w; // dropped bc no interest + c3_w inv_w; // non-fatal invariant violation + c3_w dup_w; // duplicates +} u3_mesa_stat; + +#define MESA_DESC_STRANGE "dropped strange packet" +#define MESA_FIELD_STRANGE dop_w + +#define MESA_DESC_SERIAL "dropped packet (serialisation)" +#define MESA_FIELD_SERIAL ser_w + +#define MESA_DESC_AUTH "dropped packet (authentication)" +#define MESA_FIELD_AUTH aut_w + +#define MESA_DESC_INVARIANT "invariant violation" +#define MESA_FIELD_INVARIANT inv_w + +#define MESA_DESC_APATHY "dropped packet (no interest)" +#define MESA_FIELD_APATHY apa_w + +#define MESA_DESC_DUPE "dropped packet (duplicate)" +#define MESA_FIELD_DUPE dup_w + +// routing table sentinels +#define MESA_CZAR 1 // pending dns lookup +#define MESA_ROUT 2 // have route +// +// hop enum + +#define _mesa_met3_w(a_w) ((c3_bits_word(a_w) + 0x7) >> 3) + +struct _u3_mesa_pact; + +typedef struct _u3_pact_stat { + c3_y tie_y; // tries + c3_d sen_d; // last sent + c3_y sip_y; // skips +} u3_pact_stat; + +struct _u3_mesa; + +typedef struct _u3_misord_buf { + c3_y* fra_y; + c3_w len_w; + lss_pair* par_u; +} u3_misord_buf; + +typedef struct _u3_gage { + c3_w rtt_w; // rtt + c3_w rto_w; // rto + c3_w rtv_w; // rttvar + c3_w wnd_w; // cwnd + c3_w wnf_w; // cwnd fraction + c3_w sst_w; // ssthresh + c3_w con_w; // counter + // + uv_timer_t tim_u; +} u3_gage; + +struct _u3_mesa; + +typedef struct _u3_mesa_pict { + uv_udp_send_t snd_u; + struct _u3_mesa* sam_u; + u3_mesa_pact pac_u; +} u3_mesa_pict; + +typedef struct _u3_czar_info { + c3_w pip_w; // IP of galaxy + c3_y imp_y; // galaxy number + struct _u3_mesa* sam_u; // backpointer + time_t tim_t; // time of retrieval + c3_c* dns_c; // domain + u3_noun pen; // (list @) of pending packet +} u3_czar_info; + +typedef struct _u3_lane_state { + c3_d sen_d; // last sent date + c3_d her_d; // last heard date + c3_w rtt_w; // round-trip time + c3_w rtv_w; // round-trip time variance +} u3_lane_state; + +/* _u3_mesa: next generation networking + */ +typedef struct _u3_mesa { + u3_auto car_u; + u3_pier* pir_u; + union { + uv_udp_t wax_u; + uv_handle_t had_u; + }; + u3_mesa_stat sat_u; // statistics + c3_l sev_l; // XX: ?? + c3_o for_o; // is forwarding + ur_cue_test_t* tes_u; // cue-test handle + u3_cue_xeno* sil_u; // cue handle + u3p(u3h_root) her_p; // (map ship u3_peer) + u3p(u3h_root) pac_p; // packet cache + u3p(u3h_root) lan_p; // lane cache + u3p(u3h_root) pit_p; // (map path [our=? las=(set lane)]) + u3_czar_info imp_u[256]; // galaxy information + c3_c* dns_c; // turf (urb.otrg) + c3_d tim_d; // XX: remove +} u3_mesa; + +typedef struct _u3_peer { + u3_mesa* sam_u; // backpointer + c3_o ful_o; // has this been initialized? + u3_lane dan_u; // direct lane (nullable) + u3_lane_state dir_u; // direct lane state + c3_y imp_y; // galaxy @p + u3_lane_state ind_u; // indirect lane state + u3p(u3h_root) req_p; // (map [rift path] u3_pend_req) +} u3_peer; + +typedef struct _u3_pend_req { + u3_peer* per_u; // backpointer + c3_d nex_d; // number of the next fragment to be sent + c3_d tof_d; // total number of expected fragments + c3_d tob_d; // total number of expected bytes + u3_auth_data aut_u; // message authenticator + uv_timer_t tim_u; // timehandler + c3_y* dat_y; // ((mop @ud *) lte) + c3_d hav_d; // how many fragments we've received + c3_d lef_d; // lowest fragment number currently in flight/pending + c3_d old_d; // frag num of oldest packet sent + c3_d ack_d; // highest acked fragment number + u3_gage* gag_u; // congestion control + u3_misord_buf mis_u[8]; // misordered packets + lss_verifier* los_u; // Lockstep verifier + u3_mesa_pict* pic_u; // preallocated request packet + u3_pact_stat* wat_u; // ((mop @ud packet-state) lte) + u3_bitset was_u; // ((mop @ud ?) lte) + c3_y pad_y[64]; + // stats TODO: use + c3_d beg_d; // date when request began +} u3_pend_req; + +typedef enum _u3_mesa_ctag { + CTAG_WAIT = 1, + CTAG_ITEM = 2, + CTAG_BLOCK = 3, +} u3_mesa_ctag; + +// jumbo frame cache value +// +typedef struct _u3_mesa_line { + u3_mesa_ctag typ_y; // pending or present? + u3_mesa_name nam_u; // full name for data, ready to serialize + u3_auth_data aut_u; // message authenticator + c3_w tob_d; // number of bytes in whole message + c3_w dat_w; // size in bytes of dat_y + c3_w len_w; // total allocated size, in bytes + c3_y* tip_y; // initial Merkle spine, nullable + c3_y* dat_y; // fragment data (1024 bytes per fragment) + c3_y* haz_y; // hash pairs (64 bytes per fragment) +} u3_mesa_line; + +/* + * typedef u3_mesa_req u3_noun + * [tot=@ waiting=(set @ud) missing=(set @ud) nex=@ud dat=(map @ud @)] + */ + +typedef struct _u3_cace_enty { + u3_mesa_ctag typ_y; + union { + // u03_mesa_cace_wait wat_u; + // u3_mesa_cace_item res_u; + }; +} u3_cace_enty; + +// Sent request +// because of lifecycles a u3_mesa_pact may have several libuv +// callbacks associated with it, so we can't those as callback +// instead just alloc new buffer and stick here +typedef struct _u3_seal { + uv_udp_send_t snd_u; // udp send request + u3_mesa* sam_u; + c3_w len_w; + c3_y* buf_y; +} u3_seal; + +static c3_d +get_millis() { + struct timeval tp; + + gettimeofday(&tp, NULL); + return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); + // Convert the seconds to milliseconds by multiplying by 1000 + // Convert the microseconds to milliseconds by dividing by 1000 +} + +static void +_log_buf(c3_y* buf_y, c3_w len_w) +{ + for( c3_w i_w = 0; i_w < len_w; i_w++ ) { + fprintf(stderr, "%02x", buf_y[i_w]); + } + fprintf(stderr, "\r\n"); +} + +static void +_log_gage(u3_gage* gag_u) +{ + u3l_log("gauge"); + u3l_log("rtt: %f", ((double)gag_u->rtt_w / 1000)); + u3l_log("rto: %f", ((double)gag_u->rto_w / 1000)); + u3l_log("rttvar: %f", ((double)gag_u->rtv_w / 1000)); + u3l_log("cwnd: %u", gag_u->wnd_w); + u3l_log("cwnd fraction: %f", gag_u->wnf_w / (float)gag_u->wnd_w ); + u3l_log("ssthresh: %u", gag_u->sst_w); + u3l_log("counter: %u", gag_u->con_w); + //u3l_log("algorithm: %s", gag_u->alg_c); +} + +static void +_log_lane(u3_lane* lan_u) +{ + u3l_log("mesa: lane (%s,%u)", u3r_string(u3dc("scot", c3__if, u3i_word(lan_u->pip_w))), lan_u->por_s); +} + +static void _log_peer(u3_peer* per_u) +{ + if ( per_u == NULL ) { + u3l_log("NULL peer"); + return; + } + u3l_log("dir"); + _log_lane(&per_u->dan_u); + u3l_log("galaxy: %s", u3r_string(u3dc("scot", 'p', per_u->imp_y))); +} + +static void +_log_czar_info(u3_czar_info* zar_u) +{ + { + u3_noun nam = u3dc("scot", 'p', zar_u->imp_y); + u3l_log("czar: %s", u3r_string(nam)); + u3_noun pip = u3dc("scot", c3__if, zar_u->pip_w); + u3l_log("IP: %s", u3r_string(pip)); + u3l_log("time: %" PRIu64, (c3_d)zar_u->tim_t); + u3l_log("dns: %s", zar_u->dns_c != NULL ? zar_u->dns_c : "NO DNS"); + u3l_log("pending: %u", u3r_word(0, u3do("lent", zar_u->pen))); + } +} + +static void +_log_pend_req(u3_pend_req* req_u) +{ + if( req_u == NULL ) { + u3l_log("pending request was NULL"); + return; + } + u3l_log("have: %"PRIu64, req_u->hav_d); + u3l_log("next: %"PRIu64, req_u->nex_d); + u3l_log("total: %" PRIu64, req_u->tof_d); + u3l_log("gage: %c", req_u->gag_u == NULL ? 'n' : 'y'); + //u3l_log("timer in: %" PRIu64 " ms", uv_timer_get_due_in(&req_u->tim_u)); +} + +static void +_log_mesa_data(u3_mesa_data dat_u) +{ + u3l_log("total bytes: %" PRIu64, dat_u.tob_d); + u3l_log("frag len: %u", dat_u.len_w); + // u3l_log("frag: %xxx", dat_u.fra_y); +} + +/* _mesa_lop(): find beginning of page containing fra_d +*/ +static inline c3_d +_mesa_lop(c3_d fra_d) +{ + return fra_d & ~((1 << u3_Host.ops_u.jum_y) - 1); +} + +static c3_d +_get_now_micros() +{ + struct timeval tim_u; + gettimeofday(&tim_u, NULL); + return (tim_u.tv_sec * 1000 * 1000) + tim_u.tv_usec; +} + +static c3_d +_abs_dif(c3_d ayy_d, c3_d bee_d) +{ + return ayy_d > bee_d ? ayy_d - bee_d : bee_d - ayy_d; +} + +static c3_d +_clamp_rto(c3_d rto_d) { + return c3_min(c3_max(rto_d, 200 * 1000), 25000 * 1000); // ~s25 max backoff +} + +static inline c3_o +_mesa_is_lane_zero(u3_lane* lan_u) +{ + return __(0 == lan_u->pip_w && 0 == lan_u->por_s); +} + +static c3_o +_mesa_is_direct_mode(u3_peer* per_u) +{ + c3_d now_d = _get_now_micros(); + return __(per_u->dir_u.her_d + DIRECT_ROUTE_TIMEOUT_MICROS > now_d); +} + +static c3_c* +_mesa_czar_dns(c3_y imp_y, c3_c* zar_c) +{ + u3_noun nam = u3dc("scot", 'p', imp_y); + c3_c* nam_c = u3r_string(nam); + c3_w len_w = 3 + strlen(nam_c) + strlen(zar_c); + u3_assert(len_w <= 256); + c3_c* dns_c = c3_calloc(len_w); + + c3_i sas_i = snprintf(dns_c, len_w, "%s.%s.", nam_c + 1, zar_c); + u3_assert(sas_i <= 255); + + c3_free(nam_c); + u3z(nam); + + return dns_c; +} + +/* _mesa_encode_path(): produce buf_y as a parsed path +*/ +static u3_noun +_mesa_encode_path(c3_w len_w, c3_y* buf_y) +{ + u3_noun pro; + u3_noun* lit = &pro; + + { + u3_noun* hed; + u3_noun* tel; + c3_y* fub_y = buf_y; + c3_y car_y; + c3_w tem_w; + u3i_slab sab_u; + + while ( len_w-- ) { + car_y = *buf_y++; + if ( len_w == 0 ) { + buf_y++; + car_y = 47; + } + + if ( 47 == car_y ) { + tem_w = buf_y - fub_y - 1; + u3i_slab_bare(&sab_u, 3, tem_w); + sab_u.buf_w[sab_u.len_w - 1] = 0; + memcpy(sab_u.buf_y, fub_y, tem_w); + + *lit = u3i_defcons(&hed, &tel); + *hed = u3i_slab_moot(&sab_u); + lit = tel; + fub_y = buf_y; + } + } + } + + *lit = u3_nul; + + return pro; +} + +// does not free the line itself, only its contents +static void +_mesa_free_line(u3_mesa_line* lin_u) +{ + c3_free(lin_u->nam_u.pat_c); + c3_free(lin_u->tip_y); +} + +static void +_mesa_copy_auth_data(u3_auth_data* des_u, u3_auth_data* src_u) +{ + des_u->typ_e = src_u->typ_e; + switch ( des_u->typ_e ) { + case AUTH_HMAC: { + memcpy(des_u->mac_y, src_u->mac_y, 16); + } break; + case AUTH_SIGN: { + memcpy(des_u->sig_y, src_u->sig_y, 64); + } break; + case AUTH_PAIR: { + memcpy(des_u->has_y, src_u->has_y, 64); + } break; + case AUTH_NONE: { + } break; + default: u3_assert(!"unreachable"); + } +} + +static void +_mesa_copy_name(u3_mesa_name* des_u, u3_mesa_name* src_u) +{ + memcpy(des_u, src_u, sizeof(u3_mesa_name)); + u3_ship_copy(des_u->her_u, src_u->her_u); + des_u->pat_c = c3_calloc(src_u->pat_s + 1); // null-terminate + memcpy(des_u->pat_c, src_u->pat_c, src_u->pat_s); +} + +static u3_mesa_name* +_mesa_copy_name_alloc(u3_mesa_name* src_u) +{ + u3_mesa_name* des_u = c3_calloc(sizeof(u3_mesa_name)); + _mesa_copy_name(des_u, src_u); + return des_u; +} + +static void +_mesa_free_name(u3_mesa_name* nam_u) +{ + c3_free(nam_u->pat_c); + c3_free(nam_u); +} + +static void +_mesa_free_pict(u3_mesa_pict* pic_u) +{ + mesa_free_pact(&pic_u->pac_u); + c3_free(pic_u); +} + +static u3_atom +_dire_etch_ud(c3_d num_d) +{ + c3_y hun_y[26]; + c3_y* buf_y = u3s_etch_ud_smol(num_d, hun_y); + c3_w dif_w = (c3_p)buf_y - (c3_p)hun_y; + return u3i_bytes(26 - dif_w, buf_y); // XX known-non-null +} + +static u3_mesa_line* +_mesa_new_line(u3_mesa_name* nam_u) +{ + u3_mesa_line* lin_u = c3_calloc(sizeof(u3_mesa_line)); + lin_u->typ_y = CTAG_ITEM; + _mesa_copy_name(&lin_u->nam_u, nam_u); + return lin_u; +} + +/* _mesa_request_key(): produce key for request hashtable sam_u->req_p from nam_u +*/ +u3_noun +_mesa_request_key(u3_mesa_name* nam_u) +{ + u3_noun pax = _mesa_encode_path(nam_u->pat_s, (c3_y*)nam_u->pat_c); + u3_noun res = u3nc(u3i_word(nam_u->rif_w), pax); + return res; +} + +static void +_init_gage(u3_gage* gag_u) // microseconds +{ + gag_u->rto_w = 1000 * 1000 * 1000; // ~s1 + gag_u->rtt_w = 1000 * 1000 * 1000; // ~s1 + gag_u->rtv_w = 1000 * 1000 * 1000; // ~s1 + gag_u->con_w = 0; + gag_u->wnd_w = 1; + gag_u->sst_w = 10000; +} + +/* u3_mesa_encode_lane(): serialize lane to noun +*/ +static u3_noun +u3_mesa_encode_lane(u3_lane lan_u) { + // [%if ip=@ port=@] + return u3nt(c3__if, u3i_word(lan_u.pip_w), lan_u.por_s); +} + +// lane cache is (map [lane @p] lane-info) +// +static u3_noun +_mesa_lane_key(u3_ship her_u, u3_lane* lan_u) +{ + return u3nc(u3_ship_to_noun(her_u), u3_mesa_encode_lane(*lan_u)); +} + +// TODO: all the her_p hashtable functions are not refcounted properly +static u3_peer* +_mesa_get_peer_raw(u3_mesa* sam_u, u3_noun her) +{ + u3_peer* ret_u = NULL; + u3_weak res = u3h_git(sam_u->her_p, her); + + if ( res != u3_none && res != u3_nul ) { + ret_u = u3to(u3_peer, res); + } + + u3z(her); + return ret_u; +} + +/* + * RETAIN + */ +static u3_peer* +_mesa_get_peer(u3_mesa* sam_u, u3_ship her_u) +{ + return _mesa_get_peer_raw(sam_u, u3_ship_to_noun(her_u)); +} + +static void +_mesa_put_peer_raw(u3_mesa* sam_u, u3_noun her, u3_peer* per_u) +{ + u3_peer* old_u = _mesa_get_peer_raw(sam_u, u3k(her)); + u3_peer* new_u = NULL; + + if ( old_u == NULL ) { + new_u = u3a_calloc(sizeof(u3_peer),1); + memcpy(new_u, per_u, sizeof(u3_peer)); + } else if ( new_u != old_u ) { + new_u = old_u; + memcpy(new_u, per_u, sizeof(u3_peer)); + } + + u3_noun val = u3of(u3_peer, new_u); + u3h_put(sam_u->her_p, her, val); + u3z(her); +} + +static void +_mesa_put_peer(u3_mesa* sam_u, u3_ship her_u, u3_peer* per_u) +{ + _mesa_put_peer_raw(sam_u, u3_ship_to_noun(her_u), per_u); +} + +/* _mesa_get_request(): produce pending request state for nam_u + * + * produces a NULL pointer if no pending request exists +*/ +static u3_pend_req* +_mesa_get_request(u3_mesa* sam_u, u3_mesa_name* nam_u) { + u3_pend_req* ret_u = NULL; + + u3_peer* per_u = _mesa_get_peer(sam_u, nam_u->her_u); + if ( !per_u ) { + return ret_u; + } + u3_noun key = _mesa_request_key(nam_u); + u3_weak res = u3h_git(per_u->req_p, key); + + if ( res != u3_none && res != u3_nul ) { + ret_u = u3to(u3_pend_req, res); + } + + u3z(key); + return ret_u; +} +static void +_mesa_del_request_cb(uv_handle_t* han_u) { + u3_pend_req* req_u = han_u->data; + bitset_free(&req_u->was_u); + _mesa_free_pict(req_u->pic_u); + c3_free(req_u->wat_u); + lss_verifier_free(req_u->los_u); + u3a_free(req_u); +} + +static void +_mesa_del_request(u3_mesa* sam_u, u3_mesa_name* nam_u) { + u3_peer* per_u = _mesa_get_peer(sam_u, nam_u->her_u); + if ( !per_u ) { + return; + } + u3_noun key = _mesa_request_key(nam_u); + + u3_weak req = u3h_get(per_u->req_p, key); + if ( req == u3_none ) { + u3z(key); + return; + } + u3_pend_req* req_u = u3to(u3_pend_req, req); + // u3l_log("wat_u %p", req_u->wat_u); + // u3l_log("was_u buf %p", req_u->was_u.buf_y); + uv_timer_stop(&req_u->tim_u); + + u3h_del(per_u->req_p, key); + u3z(key); + req_u->tim_u.data = req_u; + uv_close((uv_handle_t*)&req_u->tim_u, _mesa_del_request_cb); +} + +/* _mesa_put_request(): save new pending request state for nam_u + * + * the memory in the hashtable is allocated once in the lifecycle of the + * request. req_u will be copied into the hashtable memory, and so can be + * immediately freed + * +*/ +static u3_pend_req* +_mesa_put_request(u3_mesa* sam_u, u3_mesa_name* nam_u, u3_pend_req* req_u) { + u3_peer* per_u = _mesa_get_peer(sam_u, nam_u->her_u); + if ( !per_u ) { + return NULL; + } + u3_noun key = _mesa_request_key(nam_u); + + if ( req_u == NULL) { + u3h_put(per_u->req_p, key, u3_nul); + u3z(key); + return req_u; + } + u3_pend_req* old_u = _mesa_get_request(sam_u, nam_u); + u3_pend_req* new_u = req_u; + if ( old_u == NULL ) { + new_u = u3a_calloc(1, sizeof(u3_pend_req)); + /* u3l_log("putting fresh req %p", new_u); */ + memcpy(new_u, req_u, sizeof(u3_pend_req)); + new_u->per_u = per_u; + uv_timer_init(u3L, &new_u->tim_u); + } else { + new_u = old_u; + memcpy(new_u, req_u, sizeof(u3_pend_req)); + } + + u3_noun val = u3of(u3_pend_req, new_u); + u3h_put(per_u->req_p, key, val); + u3z(key); + return new_u; +} + +/* _ames_czar_port(): udp port for galaxy. + XX copied from io/ames.c +*/ +static c3_s +_ames_czar_port(c3_y imp_y) +{ + if ( c3n == u3_Host.ops_u.net ) { + return 31337 + imp_y; + } + else { + return 13337 + imp_y; + } +} + +static u3_lane +_mesa_get_direct_lane_raw(u3_mesa* sam_u, u3_noun her) +{ + if ( (c3y == u3a_is_cat(her)) && (her < 256) ) { + c3_s por_s = _ames_czar_port(her); + return (u3_lane){sam_u->imp_u[her].pip_w, por_s}; + } + u3_peer* per_u = _mesa_get_peer_raw(sam_u, her); + if ( !per_u ) { + return (u3_lane){0,0}; + } + return per_u->dan_u; +} + +static c3_o +_mesa_lanes_equal(u3_lane* lan_u, u3_lane* lon_u) +{ + return __((lan_u->pip_w == lon_u->pip_w) && (lan_u->por_s == lon_u->por_s)); +} + +static u3_lane +_mesa_get_direct_lane(u3_mesa* sam_u, u3_ship her_u) +{ + return _mesa_get_direct_lane_raw(sam_u, u3_ship_to_noun(her_u)); +} + +static u3_lane +_mesa_get_czar_lane(u3_mesa* sam_u, c3_y imp_y) +{ + c3_s por_s = _ames_czar_port(imp_y); + return (u3_lane){sam_u->imp_u[imp_y].pip_w, por_s}; +} + +static u3_lane +_mesa_get_indirect_lane(u3_mesa* sam_u, u3_noun her, u3_noun lan) +{ + if ( (c3y == u3a_is_cat(her)) && (her < 256) ) { + return _mesa_get_czar_lane(sam_u, her); + } + u3_peer* per_u = _mesa_get_peer_raw(sam_u, her); + if ( !per_u ) { + return (u3_lane){0,0}; + } + return _mesa_get_czar_lane(sam_u, per_u->imp_y); +} + +/* RETAIN +*/ +static u3_gage* +_mesa_get_lane_raw(u3_mesa* sam_u, u3_noun key) +{ + u3_gage* ret_u = NULL; + u3_weak res = u3h_git(sam_u->lan_p, key); + + if ( res != u3_none && res != u3_nul ) { + ret_u = u3to(u3_gage, res); + } + + return ret_u; +} + +/* _mesa_get_lane(): get lane +*/ +static u3_gage* +_mesa_get_lane(u3_mesa* sam_u, u3_ship her_u, u3_lane* lan_u) { + u3_noun key =_mesa_lane_key(her_u, lan_u); + u3_gage* ret_u = _mesa_get_lane_raw(sam_u, key); + u3z(key); + return ret_u; +} + +/* _mesa_put_lane(): put lane state in state + * + * uses same copying trick as _mesa_put_request() +*/ +static void +_mesa_put_lane(u3_mesa* sam_u, u3_ship her_u, u3_lane* lan_u, u3_gage* gag_u) +{ + u3_noun key = _mesa_lane_key(her_u, lan_u); + u3_gage* old_u = _mesa_get_lane_raw(sam_u, key); + u3_gage* new_u = gag_u; + + if ( old_u == NULL ) { + new_u = u3a_calloc(sizeof(u3_gage),1); + memcpy(new_u, gag_u, sizeof(u3_gage)); + + } else { + new_u = old_u; + memcpy(new_u, gag_u, sizeof(u3_gage)); + } + + u3_noun val = u3of(u3_gage, new_u); + u3h_put(sam_u->lan_p, key, val); + u3z(key); +} +// congestion control update +static void _mesa_handle_ack(u3_gage* gag_u, u3_pact_stat* pat_u) +{ + /* _log_gage(gag_u); */ + gag_u->con_w++; + + c3_d now_d = _get_now_micros(); + c3_d rtt_d = now_d < pat_u->sen_d ? 0 : now_d - pat_u->sen_d; + + c3_d err_d = _abs_dif(rtt_d, gag_u->rtt_w); + + gag_u->rtt_w = (rtt_d + (gag_u->rtt_w * 7)) >> 3; + gag_u->rtv_w = (err_d + (gag_u->rtv_w * 7)) >> 3; + gag_u->rto_w = _clamp_rto(gag_u->rtt_w + (4*gag_u->rtv_w)); + + if ( gag_u->wnd_w < gag_u->sst_w ) { + gag_u->wnd_w++; + } else if ( gag_u->wnd_w <= ++gag_u->wnf_w ) { + gag_u->wnd_w++; + gag_u->wnf_w = 0; + } +} + +static inline c3_d +_mesa_req_get_remaining(u3_pend_req* req_u) +{ + return req_u->tof_d - req_u->hav_d; +} + +/* + * _mesa_req_get_cwnd(): produce packets to send + * + * saves next fragment number and preallocated pact into the passed pointers. + * Will not do so if returning 0 +*/ +static c3_w +_mesa_req_get_cwnd(u3_pend_req* req_u) +{ + c3_w liv_w = bitset_wyt(&req_u->was_u); + c3_w rem_w = _mesa_req_get_remaining(req_u); + return c3_min(rem_w, req_u->gag_u->wnd_w - liv_w); +} + +/* _mesa_req_pact_sent(): mark packet as sent +** +*/ +static void +_mesa_req_pact_resent(u3_pend_req* req_u, u3_mesa_name* nam_u) +{ + c3_d now_d = _get_now_micros(); + // if we dont have pending request noop + if ( NULL == req_u ) { + return; + } + + req_u->wat_u[nam_u->fra_d].sen_d = now_d; + req_u->wat_u[nam_u->fra_d].tie_y++; +} + +/* _mesa_req_pact_sent(): mark packet as sent +** after 1-RT first packet is handled in _mesa_req_pact_init() +*/ +static void +_mesa_req_pact_sent(u3_pend_req* req_u, u3_mesa_name* nam_u) +{ + c3_d now_d = _get_now_micros(); + // if we already have pending request + if ( NULL != req_u ) { + if( req_u->nex_d == nam_u->fra_d ) { + req_u->nex_d++; + } + // TODO: optional assertions? + /* req_u->wat_u[nam_u->fra_w] = (u3_pact_stat){now_d, 0, 1, 0 }; */ + req_u->wat_u[nam_u->fra_d].sen_d = now_d; + req_u->wat_u[nam_u->fra_d].sip_y = 0; + req_u->wat_u[nam_u->fra_d].tie_y = 1; + + #ifdef MESA_DEBUG + /* u3l_log("bitset_put %"PRIu64, nam_u->fra_d); */ + #endif + bitset_put(&req_u->was_u, nam_u->fra_d); + } else { + u3l_log("mesa: no req for sent"); + return; + } + + if ( req_u->lef_d != 0 && c3n == bitset_has(&req_u->was_u, req_u->lef_d) ) { + while (req_u->lef_d < req_u->tof_d) { + if ( c3y == bitset_has(&req_u->was_u, req_u->lef_d) ) { + break; + } + req_u->lef_d++; + } + } +} + +/* _ames_alloc(): libuv buffer allocator. +*/ +static void +_ames_alloc(uv_handle_t* had_u, + size_t len_i, + uv_buf_t* buf + ) +{ + // we allocate 2K, which gives us plenty of space + // for a single ames packet (max size 1060 bytes) + // + void* ptr_v = c3_malloc(4096); + *buf = uv_buf_init(ptr_v, 4096); +} + +/* u3_mesa_decode_lane(): deserialize noun to lane; 0.0.0.0:0 if invalid +*/ +static u3_lane +u3_mesa_decode_lane(u3_atom lan) { + u3_lane lan_u; + c3_d lan_d; + + if ( c3n == u3r_safe_chub(lan, &lan_d) || (lan_d >> 48) != 0 ) { + return (u3_lane){0, 0}; + } + + u3z(lan); + + lan_u.pip_w = (c3_w)lan_d; + lan_u.por_s = (c3_s)(lan_d >> 32); + // convert incoming localhost to outgoing localhost + // + lan_u.pip_w = ( 0 == lan_u.pip_w ) ? 0x7f000001 : lan_u.pip_w; + + return lan_u; +} + +// END plagariasm zone +// +// +// +// +// +// +static void _mesa_free_seal(u3_seal* sel_u) +{ + c3_free(sel_u->buf_y); + c3_free(sel_u); +} + +static u3_noun _mesa_get_now() { + struct timeval tim_u; + gettimeofday(&tim_u, 0); + u3_noun res = u3_time_in_tv(&tim_u); + return res; +} + +static void +_mesa_send_cb(uv_udp_send_t* req_u, c3_i sas_i) +{ + u3_seal* sel_u = (u3_seal*)req_u; + u3_mesa* sam_u = sel_u->sam_u; + + if ( sas_i ) { + u3l_log("mesa: send fail_async: %s", uv_strerror(sas_i)); + //sam_u->fig_u.net_o = c3n; + } + else { + //sam_u->fig_u.net_o = c3y; + } + + _mesa_free_seal(sel_u); +} + +static void _mesa_send_buf(u3_mesa* sam_u, u3_lane lan_u, c3_y* buf_y, c3_w len_w) +{ + u3_seal* sel_u = c3_calloc(sizeof(*sel_u)); + sel_u->buf_y = buf_y; + sel_u->len_w = len_w; + sel_u->sam_u = sam_u; + struct sockaddr_in add_u; + + memset(&add_u, 0, sizeof(add_u)); + add_u.sin_family = AF_INET; + c3_w pip_w = c3y == u3_Host.ops_u.net ? lan_u.pip_w : 0x7f000001; + c3_s por_s = lan_u.por_s; + add_u.sin_addr.s_addr = htonl(pip_w); + add_u.sin_port = htons(por_s); + +#ifdef MESA_DEBUG + c3_c* sip_c = inet_ntoa(add_u.sin_addr); + /* u3l_log("mesa: sending packet to %s:%u", sip_c, por_s); */ +#endif + + uv_buf_t buf_u = uv_buf_init((c3_c*)buf_y, len_w); + + c3_i sas_i = uv_udp_send(&sel_u->snd_u, + &u3_Host.wax_u, + &buf_u, 1, + (const struct sockaddr*)&add_u, + _mesa_send_cb); + + if ( sas_i ) { + u3l_log("ames: send fail_sync: %s", uv_strerror(sas_i)); + /*if ( c3y == sam_u->fig_u.net_o ) { + //sam_u->fig_u.net_o = c3n; + }*/ + _mesa_free_seal(sel_u); + } +} + +static void _mesa_send(u3_mesa_pict* pic_u, u3_lane* lan_u) +{ + u3_mesa* sam_u = pic_u->sam_u; + c3_y *buf_y = c3_calloc(PACT_SIZE); + c3_w len_w = mesa_etch_pact_to_buf(buf_y, PACT_SIZE, &pic_u->pac_u); + _mesa_send_buf(sam_u, *lan_u, buf_y, len_w); +} + +typedef struct _u3_mesa_request_data { + u3_mesa* sam_u; + u3_ship her_u; + u3_mesa_name* nam_u; + c3_y* buf_y; + c3_w len_w; + u3_noun las; +} u3_mesa_request_data; + +typedef struct _u3_mesa_resend_data { + uv_timer_t tim_u; + u3_mesa_request_data dat_u; + c3_y ret_y; // number of remaining retries +} u3_mesa_resend_data; + +static void +_mesa_free_request_data(u3_mesa_request_data* dat_u) +{ + _mesa_free_name(dat_u->nam_u); + c3_free(dat_u->buf_y); + u3z(dat_u->las); + // does not free dat_u itself, since it could be in a u3_mesa_resend_data +} + +static void +_mesa_free_cb(uv_handle_t *han_u) +{ + u3_mesa_resend_data* res_u = han_u->data; + _mesa_free_request_data(&res_u->dat_u); + c3_free(res_u); +} + +static void +_mesa_free_resend_data(u3_mesa_resend_data* res_u) +{ + uv_timer_stop(&res_u->tim_u); + res_u->tim_u.data = res_u; + uv_close((uv_handle_t*)&res_u->tim_u, _mesa_free_cb); +} + +static void +_mesa_send_bufs(u3_mesa* sam_u, + u3_peer* per_u, + c3_y* buf_y, + c3_w len_w, + u3_noun las); + +static void +_mesa_send_modal(u3_peer* per_u, c3_y* buf_y, c3_w len_w) +{ + u3_mesa* sam_u = per_u->sam_u; + c3_d now_d = _get_now_micros(); + + c3_y* sen_y = c3_calloc(len_w); + memcpy(sen_y, buf_y, len_w); + + u3_ship gal_u = {0}; + gal_u[0] = per_u->imp_y; + c3_o our_o = u3_ships_equal(gal_u, sam_u->pir_u->who_d); + + if ( ( c3y == _mesa_is_direct_mode(per_u) ) || + // if we are the sponsor of the ship, don't send to ourselves + (our_o == c3y) ) { + // u3l_log("mesa: direct"); + _mesa_send_buf(sam_u, per_u->dan_u, sen_y, len_w); + per_u->dir_u.sen_d = now_d; + } + else { + + #ifdef MESA_DEBUG + c3_c* gal_c = u3_ship_to_string(gal_u); + u3l_log("mesa: sending to %s", gal_c); + c3_free(gal_c); + #endif + // XX if we have lanes in arvo, send it also there? + // otherwise after a peer turns indirect because we haven't contacted them, + // we never achieve a direct route since we only send + // to the sponsor, and all pages will come forwarded, and per_u->dir_u.her_d + // only gets updated when pages come directly, or if it's the first time + // after a restart of the driver + // + u3_lane imp_u = _mesa_get_czar_lane(sam_u, per_u->imp_y); + _mesa_send_buf(sam_u, imp_u, sen_y, len_w); + per_u->ind_u.sen_d = now_d; + + if ( (c3n == _mesa_is_lane_zero(&per_u->dan_u)) && + (per_u->dir_u.sen_d + DIRECT_ROUTE_RETRY_MICROS > now_d)) { + c3_y* san_y = c3_calloc(len_w); + memcpy(san_y, buf_y, len_w); + _mesa_send_buf(sam_u, per_u->dan_u, san_y, len_w); + per_u->dir_u.sen_d = now_d; + } + } +} + +// RETAIN on dat_u->las +static void +_mesa_send_request(u3_mesa_request_data* dat_u) +{ + u3_peer* per_u = _mesa_get_peer(dat_u->sam_u, dat_u->her_u); + if ( !per_u ) { + u3l_log("mesa: send_bufs()"); + _mesa_send_bufs(dat_u->sam_u, + NULL, + dat_u->buf_y, + dat_u->len_w, + u3k(dat_u->las)); + } + else { + u3l_log("mesa: send_modal()"); + _mesa_send_modal(per_u, dat_u->buf_y, dat_u->len_w); + } +} + +static void +_try_resend(u3_pend_req* req_u, c3_d ack_d) +{ + c3_o los_o = c3n; + c3_d now_d = _get_now_micros(); + u3_mesa_pact *pac_u = &req_u->pic_u->pac_u; + + c3_y buf_y[PACT_SIZE]; + for ( c3_d i_d = req_u->lef_d; i_d < ack_d; i_d++ ) { + // TODO: make fast recovery different from slow + // TODO: track skip count but not dupes, since dupes are meaningless + if ( (c3y == bitset_has(&req_u->was_u, i_d)) && + (now_d - req_u->wat_u[i_d].sen_d > req_u->gag_u->rto_w) ) { + los_o = c3y; + _mesa_req_pact_resent(req_u, &pac_u->pek_u.nam_u); + pac_u->pek_u.nam_u.fra_d = i_d; + c3_w len_w = mesa_etch_pact_to_buf(buf_y, PACT_SIZE, pac_u); + _mesa_send_modal(req_u->per_u, buf_y, len_w); + } + } + + if ( c3y == los_o ) { + req_u->gag_u->sst_w = c3_max(1, req_u->gag_u->wnd_w / 2); + req_u->gag_u->wnd_w = req_u->gag_u->sst_w; + req_u->gag_u->rto_w = _clamp_rto(req_u->gag_u->rto_w * 2); + } +} + +static void +_mesa_packet_timeout(uv_timer_t* tim_u); + +// TODO rename to indicate it sets a timer +static void +_update_resend_timer(u3_pend_req *req_u) +{ + if( req_u->tof_d == 0 || req_u->hav_d == req_u->tof_d ) { + u3l_log("bad condition tof_d: %"PRIu64" hav_d: %"PRIu64, + req_u->tof_d, req_u->hav_d); + return; + } + // scan in flight packets, find oldest + c3_w idx_d = req_u->lef_d; + c3_d now_d = _get_now_micros(); + c3_d wen_d = now_d; + for ( c3_d i = req_u->lef_d; i < req_u->nex_d; i++ ) { + // u3l_log("fra %u (%u)", i, __LINE__); + if ( c3y == bitset_has(&req_u->was_u, i) && + wen_d > req_u->wat_u[i].sen_d + ) { + wen_d = req_u->wat_u[i].sen_d; + idx_d = i; + } + } + if ( now_d == wen_d ) { +#ifdef MESA_DEBUG + /* u3l_log("failed to find new oldest"); */ +#endif + } + req_u->old_d = idx_d; + req_u->tim_u.data = req_u; + // c3_d gap_d = req_u->wat_u[idx_d].sen_d == 0 ? + // 0 : + // now_d - req_u->wat_u[idx_d].sen_d; + c3_d next_expiry = req_u->gag_u->rto_w; + // u3l_log("next_expiry %llu", next_expiry / 1000); + uv_timer_start(&req_u->tim_u, _mesa_packet_timeout, next_expiry / 1000, 0); +} + +/* _mesa_packet_timeout(): callback for packet timeout +*/ +static void +_mesa_packet_timeout(uv_timer_t* tim_u) { + u3_pend_req* req_u = (u3_pend_req*)tim_u->data; + /* u3l_log("%"PRIu64" packet timed out", req_u->old_d); */ + _try_resend(req_u, req_u->nex_d); + _update_resend_timer(req_u); +} + +static c3_o +_mesa_burn_misorder_queue(u3_pend_req* req_u, c3_y boq_y, c3_w lef_d) +{ + c3_w num_w; + c3_w max_w = sizeof(req_u->mis_u) / sizeof(u3_misord_buf); + c3_o res_o = c3y; + for ( num_w = 0; num_w < max_w; num_w++ ) { + u3_misord_buf* buf_u = &req_u->mis_u[num_w]; + if ( buf_u->len_w == 0 ) { + break; + } + if ( c3y != lss_verifier_ingest(req_u->los_u, buf_u->fra_y, buf_u->len_w, buf_u->par_u) ) { + res_o = c3n; + u3l_log("fail to burn %u", num_w); + c3_free(buf_u->fra_y); + c3_free(buf_u->par_u); + break; + } + c3_w siz_w = (1 << (boq_y - 3)); // XX + // u3l_log("size %u counter %u num %u fra %u inx %u lef_d %u", siz_w, req_u->los_u->counter , num_w, fra_d, (req_u->los_u->counter + num_w + 1), lef_d); + memcpy(req_u->dat_y + (siz_w * (lef_d + num_w + 1)), buf_u->fra_y, buf_u->len_w); + c3_free(buf_u->fra_y); + c3_free(buf_u->par_u); + } + + // ratchet forward + num_w++; // account for the in-ordered packet processed in _mesa_req_pact_done + req_u->lef_d += num_w; + req_u->hav_d += num_w; + + memmove(req_u->mis_u, + (c3_y*)req_u->mis_u + (num_w * sizeof(u3_misord_buf)), + (max_w - num_w) * sizeof(u3_misord_buf)); + memset((c3_y*)req_u->mis_u + ((max_w - (num_w)) * sizeof(u3_misord_buf)), 0, (num_w) * sizeof(u3_misord_buf)); + + return res_o; +} + +static void +_init_lane_state(u3_lane_state* sat_u); + +/* _mesa_req_pact_done(): mark packet as done +*/ +static void +_mesa_req_pact_done(u3_pend_req* req_u, + u3_mesa_name* nam_u, + u3_mesa_data* dat_u, + c3_y hop_y, + u3_lane lan_u) +{ + u3_mesa* sam_u = req_u->per_u->sam_u; // needed for the MESA_LOG macro + + // received past the end of the message + if ( mesa_num_leaves(dat_u->tob_d) <= nam_u->fra_d ) { + u3l_log("strange tob_d %"PRIu64" fra_d %"PRIu64" req_u %"PRIu64, + dat_u->tob_d, nam_u->fra_d, req_u->hav_d); + MESA_LOG(sam_u, STRANGE); + // XX: is this sufficient to drop whole request + return; + } + + // received duplicate + if ( c3n == bitset_has(&req_u->was_u, nam_u->fra_d) ) { + // MESA_LOG(sam_u, DUPE); + return; + } + + lss_pair* par_u = NULL; + if ( dat_u->aut_u.typ_e == AUTH_PAIR ) { + // needs to be heap allocated bc will be saved if misordered + par_u = c3_calloc(sizeof(lss_pair)); + memcpy((*par_u)[0], dat_u->aut_u.has_y[0], sizeof(lss_hash)); + memcpy((*par_u)[1], dat_u->aut_u.has_y[1], sizeof(lss_hash)); + } + + if ( req_u->los_u->counter != nam_u->fra_d ) { + if ( nam_u->fra_d < req_u->los_u->counter ) { + // u3l_log("fragment number too low: %"PRIu64, nam_u->fra_d); + c3_free(par_u); + return; + } else if ( nam_u->fra_d >= req_u->los_u->counter + (sizeof(req_u->mis_u)/sizeof(u3_misord_buf)) ) { + // u3l_log("fragment number too high: %"PRIu64, nam_u->fra_d); + c3_free(par_u); + return; + } else { + // insert into misordered queue + u3_misord_buf* buf_u = &req_u->mis_u[nam_u->fra_d - req_u->los_u->counter - 1]; + buf_u->fra_y = c3_calloc(dat_u->len_w); + buf_u->len_w = dat_u->len_w; + memcpy(buf_u->fra_y, dat_u->fra_y, dat_u->len_w); + buf_u->par_u = par_u; +#ifdef U3_OS_osx + u3l_log("insert into misordered queue fra: [%llu] = %llu [counter %u]", +#else + u3l_log("insert into misordered queue fra: [%lu] = %lu [counter %u]", +#endif + nam_u->fra_d - req_u->los_u->counter - 1, + nam_u->fra_d, + req_u->los_u->counter); + _mesa_handle_ack(req_u->gag_u, &req_u->wat_u[nam_u->fra_d]); + return; + } + } + else if ( c3y != lss_verifier_ingest(req_u->los_u, dat_u->fra_y, dat_u->len_w, par_u) ) { + u3l_log("auth fail frag %"PRIu64, nam_u->fra_d); + c3_free(par_u); + // TODO: do we drop the whole request on the floor? + MESA_LOG(sam_u, AUTH); + return; + } + else if ( c3y != _mesa_burn_misorder_queue(req_u, nam_u->boq_y, req_u->lef_d) ) { + u3l_log("about to misorder free"); + c3_free(par_u); + MESA_LOG(sam_u, AUTH) + return; + } + else { + // u3l_log("about to other free"); + c3_free(par_u); + } + + if ( nam_u->fra_d > req_u->ack_d ) { + req_u->ack_d = nam_u->fra_d; + } + + bitset_del(&req_u->was_u, nam_u->fra_d); // XX also for out of order frags? + + #ifdef MESA_DEBUG + // u3l_log("fragment %llu counter %llu hav_d %llu nex_d %llu ack_d %llu lef_d %llu old_d %llu", nam_u->fra_d, req_u->los_u->counter, req_u->hav_d, req_u->nex_d, req_u->ack_d, req_u->lef_d, req_u->old_d); + #endif + + u3_lane_state* sat_u; + if ( 0 == hop_y && (c3n == _mesa_lanes_equal(&lan_u, &req_u->per_u->dan_u)) ) { + req_u->per_u->dan_u = lan_u; + sat_u = &req_u->per_u->dir_u; + _init_lane_state(sat_u); + } + else { + sat_u = &req_u->per_u->ind_u; + } + sat_u->her_d = _get_now_micros(); + + // handle gauge update + _mesa_handle_ack(req_u->gag_u, &req_u->wat_u[nam_u->fra_d]); + + c3_w siz_w = (1 << (nam_u->boq_y - 3)); + memcpy(req_u->dat_y + (siz_w * nam_u->fra_d), dat_u->fra_y, dat_u->len_w); + + // XX FIXME? + _try_resend(req_u, nam_u->fra_d); // _try_resend(req_u, req_u->nex_d); + _update_resend_timer(req_u); +} + +static u3_lane +_realise_lane(u3_noun lan) { + u3_lane lan_u; + lan_u.por_s = 0; + lan_u.pip_w = 0; + + if ( c3y == u3a_is_cat(lan) ) { + // u3_assert( lan < 256 ); + if ( (c3n == u3_Host.ops_u.net) ) { + lan_u.pip_w = 0x7f000001 ; + lan_u.por_s = _ames_czar_port(lan); + } + } else { + u3_noun tag, pip, por; + u3x_trel(lan, &tag, &pip, &por); + if ( tag == c3__if ) { + lan_u.pip_w = u3r_word(0, pip); + u3_assert( c3y == u3a_is_cat(por) && por <= 0xFFFF); + lan_u.por_s = por; + } else { + u3l_log("mesa: inscrutable lane"); + } + + } + u3z(lan); + return lan_u; +} + +static void +_mesa_send_bufs(u3_mesa* sam_u, + u3_peer* per_u, // null for response packets + c3_y* buf_y, + c3_w len_w, + u3_noun las) +{ + u3_noun lan, t = u3qdi_tap(las); + + while ( t != u3_nul ) { + u3x_cell(t, &lan, &t); + u3_lane lan_u = _realise_lane(u3k(lan)); + + if ( !lan_u.por_s ) { + u3l_log("mesa: failed to realise lane"); + } else { + c3_y* sen_y = c3_calloc(len_w); + memcpy(sen_y, buf_y, len_w); + _mesa_send_buf(sam_u, lan_u, sen_y, len_w); + if ( per_u && (c3y == _mesa_lanes_equal(&lan_u, &per_u->dan_u)) ) { + per_u->dir_u.sen_d = _get_now_micros(); + } + } + } + u3z(las); u3z(lan); +} + +static void +_mesa_timer_cb(uv_timer_t* tim_u) { + u3_pend_req* req_u = tim_u->data; + _try_resend(req_u, req_u->nex_d); +} + +static void +_mesa_czar_here(u3_czar_info* imp_u, time_t now_t, struct sockaddr_in* add_u) +{ + u3_mesa* sam_u = imp_u->sam_u; + c3_y imp_y = imp_u->imp_y; + c3_w pip_w = ntohl(add_u->sin_addr.s_addr); + + if ( imp_u->pip_w != pip_w ) { + u3_noun nam = u3dc("scot", c3__if, u3i_word(pip_w)); + c3_c* nam_c = u3r_string(nam); + + u3l_log("mesa: czar %s: ip %s", imp_u->dns_c, nam_c); + + c3_free(nam_c); + u3z(nam); + } + imp_u->pip_w = pip_w; + imp_u->tim_t = now_t; + + u3_noun pac, t = imp_u->pen; + + while ( t != u3_nul ) { + u3x_cell(t, &pac, &t); + c3_w len_w = u3r_met(3,pac); + c3_y* buf_y = c3_calloc(len_w); + u3r_bytes(0, len_w, buf_y, pac); + u3_lane lan_u = (u3_lane){pip_w, _ames_czar_port(imp_y)}; + _mesa_send_buf(sam_u, lan_u, buf_y, len_w); + } + u3z(imp_u->pen); + imp_u->pen = u3_nul; +} + +static void +_mesa_czar_gone(u3_mesa* sam_u, c3_i sas_i, c3_y imp_y, time_t now_t) +{ + u3_czar_info* imp_u = &sam_u->imp_u[imp_y]; + imp_u->tim_t = now_t; + u3l_log("mesa: %s", uv_strerror(sas_i)); +} + +static void +_mesa_czar_cb(uv_getaddrinfo_t* adr_u, c3_i sas_i, struct addrinfo* aif_u) +{ + u3_czar_info* imp_u = (u3_czar_info*)adr_u->data; + c3_y imp_y = imp_u->imp_y; + u3_mesa* sam_u = imp_u->sam_u; + time_t now_t = time(0); + + if ( 0 == sas_i ) { + // XX: lifetimes for addrinfo, ames does something funny + _mesa_czar_here(imp_u, now_t, (struct sockaddr_in*)aif_u->ai_addr); + } else { + _mesa_czar_gone(sam_u, sas_i, imp_y, now_t); + } + + c3_free(adr_u); + uv_freeaddrinfo(aif_u); + +} + +static void +_mesa_resolve_czar(u3_mesa* sam_u, c3_y imp_y, u3_noun pac) +{ + u3_assert( c3y == u3_Host.ops_u.net ); + u3_czar_info* imp_u = &sam_u->imp_u[imp_y]; + time_t now_t = time(0); + time_t wen_t = imp_u->tim_t; + if ( ((now_t - wen_t) < 300) ) { + // XX: confirm validity of drop + return; + } + if ( pac != u3_nul && u3_nul != imp_u->pen ) { + // already pending, add to queue + imp_u->pen = u3nc(pac, imp_u->pen); + return; + } + if ( pac != u3_nul ) { + imp_u->pen = u3nc(pac, imp_u->pen); + } + + if ( !sam_u->dns_c ) { + u3l_log("mesa: no galaxy domain"); + return; + } + imp_u->dns_c = _mesa_czar_dns(imp_y, sam_u->dns_c); + { + uv_getaddrinfo_t* adr_u = c3_calloc(sizeof(*adr_u)); + c3_i sas_i; + adr_u->data = imp_u; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + if ( 0 != (sas_i = uv_getaddrinfo(u3L, adr_u, _mesa_czar_cb, imp_u->dns_c, 0, &hints))) { + time_t now_t = time(0); + _mesa_czar_gone(sam_u, sas_i, imp_y, now_t); + return; + } + } + + +} + +static u3_noun +_mesa_queue_czar(u3_mesa* sam_u, u3_noun las, u3_noun pac) +{ + las = u3do("flop", las); + u3_noun lan, t = las; + u3_noun res = u3_nul; + time_t now_t = time(0); + while ( t != u3_nul ) { + u3x_cell(t, &lan, &t); + if ( (c3y == u3a_is_cat(lan) && lan < 256 ) ) { + u3_czar_info* imp_u = &sam_u->imp_u[lan]; + + if ( 0 != imp_u->pip_w ) { + res = u3qdi_put(res, u3nt(c3__if, u3i_word(imp_u->pip_w), _ames_czar_port(lan))); + } + if ( c3y == u3_Host.ops_u.net ) { + _mesa_resolve_czar(sam_u, lan, u3k(pac)); + } + } else { + res = u3qdi_put(res, u3k(lan)); + } + } + u3z(las); + u3z(pac); + return res; +} + +static void _mesa_add_our_to_pit(u3_mesa*, u3_mesa_name*); + +static u3_noun +_name_to_scry(u3_mesa_name* nam_u) +{ + u3_noun rif = _dire_etch_ud(nam_u->rif_w); + u3_noun boq = _dire_etch_ud(nam_u->boq_y); + u3_noun fag = _dire_etch_ud(nam_u->fra_d); + u3_noun pax = _mesa_encode_path(nam_u->pat_s, (c3_y*)nam_u->pat_c); + + u3_noun wer = nam_u->nit_o == c3y + ? u3nc(c3__init, pax) + : u3nt(nam_u->aut_o == c3y ? c3__auth : c3__data, fag, pax); + + u3_noun res = u3nc(c3__mess, u3nq(rif, c3__pact, boq, u3nc(c3__etch, wer))); + + return res; +} + +/* + * RETAIN */ +static u3_weak +_mesa_get_pit(u3_mesa* sam_u, u3_mesa_name* nam_u) +{ + u3_noun pax = _name_to_scry(nam_u); + u3_weak res = u3h_get(sam_u->pit_p, pax); + u3z(pax); + if (c3__sent == res) { + u3z(res); + return u3_none; + } + else { + return res; + } +} + +static void +_mesa_put_pit(u3_mesa* sam_u, u3_mesa_name* nam_u, u3_noun val) +{ + u3_noun pax = _name_to_scry(nam_u); + u3h_put(sam_u->pit_p, pax, u3k(val)); + u3z(pax); + u3z(val); +} + +static void +_mesa_del_pit(u3_mesa* sam_u, u3_mesa_name* nam_u) +{ + u3_weak pin = _mesa_get_pit(sam_u, nam_u); + u3_noun pax = _name_to_scry(nam_u); + // u3m_p("_mesa_del_pit pax", pax); + if ( pin != u3_none ) { + // u3h_del(sam_u->pit_p, pax); // XX restore me + u3h_put(sam_u->pit_p, pax, c3__sent); + } else { + u3l_log("deleting non existent key in PIT"); + } + + u3z(pin); u3z(pax); +} + +static void +_mesa_add_lane_to_pit(u3_mesa* sam_u, u3_mesa_name* nam_u, u3_lane lan_u) +{ + // TODO: prevent duplicate lane from being added + u3_noun lan = u3_mesa_encode_lane(lan_u); + u3_weak pin = _mesa_get_pit(sam_u, nam_u); + if ( u3_none == pin ) { + pin = u3nc(c3n, u3nt(u3k(lan), u3_nul, u3_nul)); + } + else { + pin = //u3qdi_put(pin, u3nt(u3k(u3h(pin)), u3k(lan), u3k(u3t(pin)))); + u3nc(u3h(pin), u3qdi_put(u3t(pin), u3k(lan))); + } + _mesa_put_pit(sam_u, nam_u, u3k(pin)); + u3z(lan); u3z(pin); + return; +} + +static void +_mesa_add_our_to_pit(u3_mesa* sam_u, u3_mesa_name* nam_u) +{ + u3_weak pin = _mesa_get_pit(sam_u, nam_u); + if ( u3_none == pin ) { + pin = u3nc(c3y, u3_nul); + } + else { + pin = u3nc(c3y, u3k(u3t(pin))); + } + _mesa_put_pit(sam_u, nam_u, u3k(pin)); + u3z(pin); + return; +} + +static void +_mesa_resend_timer_cb(uv_timer_t* tim_u) +{ + u3_mesa_resend_data* res_u = (u3_mesa_resend_data*)tim_u; + u3_mesa_request_data* dat_u = &res_u->dat_u; + res_u->ret_y--; + + u3_weak pit = _mesa_get_pit(dat_u->sam_u, dat_u->nam_u); + if ( u3_none == pit ) { + #ifdef MESA_DEBUG + u3l_log("mesa: resend PIT entry gone %u", res_u->ret_y); + #endif + _mesa_free_resend_data(res_u); + return; + } + else { + #ifdef MESA_DEBUG + u3l_log("mesa: resend %u", res_u->ret_y); + #endif + } + u3z(pit); + + _mesa_send_request(dat_u); + + if ( res_u->ret_y ) { + uv_timer_start(&res_u->tim_u, _mesa_resend_timer_cb, 1000, 0); + } + else { + _mesa_free_resend_data(res_u); + } +} + +static void +_mesa_ef_send(u3_mesa* sam_u, u3_noun las, u3_noun pac) +{ + las = _mesa_queue_czar(sam_u, las, u3k(pac)); + c3_w len_w = u3r_met(3, pac); + c3_y* buf_y = c3_calloc(len_w); + u3r_bytes(0, len_w, buf_y, pac); + + u3_mesa_pact pac_u; + memset(&pac_u, 0x11, sizeof(pac_u)); + c3_c* err_c = mesa_sift_pact_from_buf(&pac_u, buf_y, len_w); + if ( err_c ) { + u3l_log("mesa: ef_send: sift failed: %u %s", len_w, err_c); + u3z(pac); + u3z(las); + return; + } + + if ( PACT_PAGE == pac_u.hed_u.typ_y ) { + u3_weak pin = _mesa_get_pit(sam_u, &pac_u.pek_u.nam_u); + + if ( u3_none == pin ) { + #ifdef MESA_DEBUG + u3l_log(" no PIT entry"); + #endif + u3z(pac); + u3z(las); + mesa_free_pact(&pac_u); + return; + } + + u3_noun our, las; + u3x_cell(pin, &our, &las); + if ( u3_nul != las ) { + _mesa_send_bufs(sam_u, NULL, buf_y, len_w, u3k(las)); + _mesa_del_pit(sam_u, &pac_u.pek_u.nam_u); + c3_free(buf_y); + u3z(pin); + } + } + else { + // TODO this is too much allocation and copying + u3_mesa_name* nam_u = _mesa_copy_name_alloc(&pac_u.pek_u.nam_u); + u3_mesa_resend_data* res_u = c3_malloc(sizeof(u3_mesa_resend_data)); + u3_mesa_request_data* dat_u = &res_u->dat_u; + { + dat_u->sam_u = sam_u; + u3_ship_copy(dat_u->her_u, nam_u->her_u); + dat_u->nam_u = nam_u; + dat_u->las = u3k(las); + dat_u->buf_y = buf_y; + dat_u->len_w = len_w; + } + { + res_u->ret_y = 4; + uv_timer_init(u3L, &res_u->tim_u); + } + _mesa_add_our_to_pit(sam_u, nam_u); + _mesa_send_request(dat_u); + uv_timer_start(&res_u->tim_u, _mesa_resend_timer_cb, 1000, 0); + } + + sam_u->tim_d = _get_now_micros(); + + mesa_free_pact(&pac_u); + u3z(pac); + u3z(las); +} + +c3_o +_ames_kick_newt(void* sam_u, u3_noun tag, u3_noun dat); + +static void _meet_peer(u3_mesa* sam_u, u3_peer* per_u, u3_ship her_u); +static void _init_peer(u3_mesa* sam_u, u3_peer* per_u); + +static c3_o _mesa_kick(u3_mesa* sam_u, u3_noun tag, u3_noun dat) +{ + c3_o ret_o; + switch ( tag ) { + default: { + ret_o = c3n; + } break; + case c3__push: { + u3_noun las, pac; + if ( c3n == u3r_cell(dat, &las, &pac) ) { + // u3l_log(" mesa: send old"); + ret_o = c3n; + } else { + // u3l_log(" mesa: send new"); + _mesa_ef_send(sam_u, u3k(las), u3k(pac)); + ret_o = c3y; + } + } break; + case c3__send: + case c3__turf: + case c3__saxo: { + #ifdef MESA_DEBUG + c3_c* tag_c = u3r_string(tag); + /* u3l_log("mesa: send old %s", tag_c); */ + c3_free(tag_c); + #endif + ret_o = _ames_kick_newt(u3_Host.sam_u, u3k(tag), u3k(dat)); + } break; + case c3__nail: { + u3m_p("data", dat); + u3_noun who = u3k(u3h(dat)); + u3_peer* per_u = _mesa_get_peer_raw(sam_u, who); + + if ( NULL == per_u ) { + per_u = c3_calloc(sizeof(u3_peer)); + _init_peer(sam_u, per_u); + } + u3_ship who_u; + u3_ship_of_noun(who_u ,who); + _meet_peer(sam_u, per_u, who_u); + + ret_o = _ames_kick_newt(u3_Host.sam_u, u3k(tag), u3k(dat)); + } break; + } + + // technically losing tag is unncessary as it always should + // be a direct atom, but better to be strict + u3z(dat); u3z(tag); + return ret_o; +} + +static c3_o _mesa_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) +{ + u3_mesa* sam_u = (u3_mesa*)car_u; + + u3_noun tag, dat, i_wir; + c3_o ret_o; + if ( (c3n == u3r_cell(wir, &i_wir, 0)) + || (c3__ames != i_wir) + || (c3n == u3r_cell(cad, &tag, &dat)) ) + { + ret_o = c3n; + } + else { + ret_o = _mesa_kick(sam_u, u3k(tag), u3k(dat)); + } + + u3z(wir); u3z(cad); + return ret_o; +} + +static u3_noun +_mesa_io_info(u3_auto* car_u) +{ + + return u3_nul; +} + +static void +_mesa_io_slog(u3_auto* car_u) { + u3l_log("mesa is online"); +} + +static void +_mesa_free_peer(u3_noun per) +{ + u3_peer* per_u = u3to(u3_peer, per); + // u3h_free(per_u->req_p); XX FIXME; refcounts wrong +} + +static void +_mesa_exit_cb(uv_handle_t* had_u) +{ + u3_mesa* sam_u = had_u->data; + + u3s_cue_xeno_done(sam_u->sil_u); + ur_cue_test_done(sam_u->tes_u); + u3h_walk(sam_u->her_p, _mesa_free_peer); + u3h_free(sam_u->her_p); + + c3_free(sam_u); +} + +static void +_mesa_io_exit(u3_auto* car_u) +{ + u3_mesa* sam_u = (u3_mesa*)car_u; + uv_close(&sam_u->had_u, _mesa_exit_cb); +} + +static void +_init_lane_state(u3_lane_state* sat_u) +{ + sat_u->sen_d = 0; + sat_u->her_d = 0; + sat_u->rtt_w = 1000000; + sat_u->rtv_w = 1000000; +} + +static void +_init_peer(u3_mesa* sam_u, u3_peer* per_u) +{ + per_u->sam_u = sam_u; + per_u->ful_o = c3n; + per_u->dan_u = (u3_lane){0,0}; + _init_lane_state(&per_u->dir_u); + per_u->imp_y = 0; + _init_lane_state(&per_u->ind_u); + per_u->req_p = u3h_new(); +} + +/* + * RETAIN + */ +static c3_o +_mesa_add_galaxy_pend(u3_mesa* sam_u, u3_noun her, u3_noun pen) +{ + u3_weak old = u3h_get(sam_u->her_p, her); + u3_noun pes = u3_nul; + u3_noun wat = {0}; + if ( u3_none != old ) { + if ( u3h(old) == MESA_CZAR ) { + u3x_cell(u3t(old), &pes, &wat); + u3z(old); + } else { + u3l_log("mesa: attempted to resolve resolved czar"); + u3z(old); + return c3n; + } + } + u3_noun val = u3nc(u3nc(u3k(pen), u3k(pes)), c3y); + u3h_put(sam_u->her_p, her, val); + u3z(val); + return _(wat); +} + +static u3_noun +_name_to_jumbo_scry(u3_mesa_name* nam_u) +{ + u3_noun rif = _dire_etch_ud(nam_u->rif_w); + u3_noun boq = _dire_etch_ud(31); // XX make configurable + u3_noun fag = _dire_etch_ud(0); // XX 1 + u3_noun pax = _mesa_encode_path(nam_u->pat_s, (c3_y*)nam_u->pat_c); + u3_noun wer = nam_u->nit_o == c3y + ? u3nc(c3__init, pax) + : u3nt(nam_u->aut_o == c3y ? c3__auth : c3__data, fag, pax); + + u3_noun res = u3nc(c3__mess, u3nq(rif, c3__pact, boq, u3nc(c3__etch, wer))); + + return res; +} + +/* + * RETAIN */ +static u3_mesa_line* +_mesa_get_jumbo_cache(u3_mesa* sam_u, u3_mesa_name* nam_u) +{ + u3_noun pax = _name_to_jumbo_scry(nam_u); + u3_weak res = u3h_get(sam_u->pac_p, pax); + #ifdef MESA_DEBUG + // u3m_p((u3_none == res)? "mesa: cache miss" : "mesa: cache hit ", pax); + #endif + u3z(pax); + return ( u3_none == res ) ? NULL : u3a_into(res); +} + +static void +_mesa_put_jumbo_cache(u3_mesa* sam_u, u3_mesa_name* nam_u, u3_mesa_line* lin_u) +{ + u3_noun pax = _name_to_jumbo_scry(nam_u); + u3_weak del = u3h_put_get(sam_u->pac_p, pax, u3a_outa(lin_u)); + if ( u3_none != del ) { + _mesa_free_line(u3a_into(u3t(del))); + u3z(del); + } + u3z(pax); +} + +static void +_mesa_send_pact(u3_mesa* sam_u, + u3_noun las, + u3_peer* per_u, // null for response packets + u3_mesa_pact* tac_u) +{ + c3_y* buf_y = c3_calloc(PACT_SIZE); + c3_w len_w = mesa_etch_pact_to_buf(buf_y, PACT_SIZE, tac_u); + _mesa_send_bufs(sam_u, per_u, buf_y, len_w, u3k(las)); + u3z(las); +} + +static void +_mesa_send_leaf(u3_mesa* sam_u, + u3_mesa_line* lin_u, + u3_mesa_pact* pac_u, // scratchpad + c3_d fra_d) +{ + u3_mesa_name* nam_u = &pac_u->pag_u.nam_u; + u3_mesa_data* dat_u = &pac_u->pag_u.dat_u; + + nam_u->fra_d = fra_d; + c3_d i_d = fra_d - (lin_u->nam_u.fra_d * (1 << u3_Host.ops_u.jum_y)); + c3_w cur_w = i_d * 1024; + dat_u->fra_y = lin_u->dat_y + cur_w; + dat_u->len_w = c3_min(lin_u->dat_w - cur_w, 1024); + + lss_pair* pair = ((lss_pair*)lin_u->haz_y) + i_d; + + if ( 0 == nam_u->fra_d ) { // XX + _mesa_copy_auth_data(&dat_u->aut_u, &lin_u->aut_u); + } else if ( 0 == memcmp(pair, &(lss_pair){0}, sizeof(lss_pair)) ) { + dat_u->aut_u.typ_e = AUTH_NONE; + }else { + dat_u->aut_u.typ_e = AUTH_PAIR; + memcpy(dat_u->aut_u.has_y, pair, sizeof(lss_pair)); + } + u3_weak pin = _mesa_get_pit(sam_u, nam_u); + if ( u3_none != pin) { + #ifdef MESA_DEBUG + // u3l_log(" sending leaf packet, fra_d: %"PRIu64, nam_u->fra_d); + #endif + // log_pact(pac_u); + _mesa_send_pact(sam_u, u3k(u3t(pin)), NULL, pac_u); + _mesa_del_pit(sam_u, nam_u); + u3z(pin); + } +} + +static void +_mesa_send_jumbo_pieces(u3_mesa* sam_u, u3_mesa_line* lin_u, c3_d* fra_u) +{ + #ifdef MESA_DEBUG + // u3l_log("mesa: send_jumbo_pieces()"); + #endif + + u3_mesa_pact pac_u = {0}; + memset(&pac_u, 0x11, sizeof(pac_u)); + + u3_mesa_head* hed_u = &pac_u.hed_u; + { + hed_u->nex_y = HOP_NONE; + hed_u->pro_y = 1; + hed_u->typ_y = PACT_PAGE; + hed_u->hop_y = 0; + // mug_w varies by fragment + } + + u3_mesa_name* nam_u = &pac_u.pag_u.nam_u; + { + _mesa_copy_name(nam_u, &lin_u->nam_u); + nam_u->boq_y = 13; + nam_u->fra_d *= (1 << u3_Host.ops_u.jum_y); // XX looks sus + } + + u3_mesa_data* dat_u = &pac_u.pag_u.dat_u; + { + dat_u->tob_d = lin_u->tob_d; + dat_u->aut_u = lin_u->aut_u; + // aut_u, len_w, and fra_y vary by fragment + } + c3_d mev_d = mesa_num_leaves(dat_u->tob_d); + c3_w pro_w = lss_proof_size(mev_d); + + // send response packet for %init request + if ( 0 == lin_u->nam_u.fra_d ) { + nam_u->nit_o = c3y; + u3_weak pin = _mesa_get_pit(sam_u, nam_u); + if ( u3_none != pin ) { + // XX lss_proof_size always returns >= 1 + // if the initial Merkle proof is nonzero, this is a multifragment + // message; send auth response to the %init request + if ( pro_w > 1 ) { + dat_u->len_w = pro_w * sizeof(lss_hash); + c3_y* pro_y = c3_malloc(dat_u->len_w); + memcpy(pro_y, lin_u->tip_y, dat_u->len_w); + dat_u->fra_y = pro_y; + _mesa_send_pact(sam_u, u3k(u3t(pin)), NULL, &pac_u); + _mesa_del_pit(sam_u, nam_u); + c3_free(pro_y); + u3z(pin); + } + // single-fragment message; just send the one data fragment + else if ( ( NULL == fra_u) || (0 == *fra_u) ) { + _mesa_send_leaf(sam_u, lin_u, &pac_u, 0); + } + else { + u3l_log("mesa: weird fragment number %"PRIu64, *fra_u); + } + } + } + // Now send responses to non-%init requests. + // note: we might re-send the first data fragment, but only if there is an + // outstanding non-%init request for it, which would be strange but not + // illegal + nam_u->nit_o = c3n; + + // send leaf packet(s) + c3_d lev_d = mesa_num_leaves(lin_u->dat_w); + c3_d fir_d = nam_u->fra_d; + c3_d las_d = fir_d + lev_d; + if ( NULL == fra_u ) { + for (c3_d fra_d = fir_d; fra_d < las_d; fra_d++) { + _mesa_send_leaf(sam_u, lin_u, &pac_u, fra_d); + } + } + else { + _mesa_send_leaf(sam_u, lin_u, &pac_u, *fra_u); + } + // mesa_free_pact(&pac_u); // TODO reinstate +} + +static void +_mesa_page_scry_jumbo_cb(void* vod_p, u3_noun res) +{ + u3_mesa_pict* pic_u = vod_p; + u3_mesa* sam_u = pic_u->sam_u; + u3_mesa_pact* pac_u = &pic_u->pac_u; + u3_mesa_name* nam_u = &pac_u->pag_u.nam_u; + + u3_weak pag = u3r_at(7, res); + + if ( u3_none == pag ) { + // TODO: mark as dead + u3z(res); + _mesa_free_pict(pic_u); + u3_mesa_line* lin_u = _mesa_get_jumbo_cache(sam_u, nam_u); + if ( NULL == lin_u ) { + return; + } + lin_u->typ_y = CTAG_BLOCK; + _mesa_put_jumbo_cache(sam_u, nam_u, lin_u); + u3l_log("mesa: jumbo frame missing"); + log_pact(pac_u); + return; + } + u3_noun pac, pas, pof; + if ( c3n == u3r_trel(pag, &pac, &pas, &pof) || + c3n == u3a_is_pug(pac) ) { + u3l_log("mesa: jumbo frame misshapen"); + _mesa_free_pict(pic_u); + log_pact(pac_u); + u3z(res); + return; + } + + #ifdef MESA_DEBUG + // u3l_log("mesa: scry_jumbo_cb()"); + // log_pact(pac_u); + #endif + + u3_mesa_line* lin_u; + { + c3_w jumbo_w = u3r_met(3, pac); + c3_y* jumbo_y = c3_calloc(jumbo_w); + u3r_bytes(0, jumbo_w, jumbo_y, pac); + + u3_mesa_pact jum_u; + c3_c* err_c = mesa_sift_pact_from_buf(&jum_u, jumbo_y, jumbo_w); + if ( err_c ) { + u3l_log("mesa: jumbo frame parse failure: %s", err_c); + log_pact(pac_u); + _mesa_free_pict(pic_u); + u3z(res); + return; + } + u3_mesa_data* dat_u = &jum_u.pag_u.dat_u; + + c3_d mev_d = mesa_num_leaves(dat_u->tob_d); // leaves in message + c3_w tip_w = // bytes in Merkle spine + (mev_d > 1 && jum_u.pag_u.nam_u.fra_d == 0)? + lss_proof_size(mev_d) * sizeof(lss_hash): + 0; + c3_w dat_w = dat_u->len_w; // bytes in fragment data in this jumbo frame + c3_w lev_w = mesa_num_leaves(dat_w); // number of leaves in this frame + c3_w haz_w = lev_w * sizeof(lss_pair); // bytes in hash pairs + c3_w len_w = tip_w + dat_w + haz_w; + + lin_u = u3a_malloc(sizeof(u3_mesa_line)); + lin_u->typ_y = CTAG_ITEM; + _mesa_copy_name(&lin_u->nam_u, &jum_u.pek_u.nam_u); + lin_u->aut_u = dat_u->aut_u; + lin_u->tob_d = dat_u->tob_d; + lin_u->dat_w = dat_w; + lin_u->len_w = len_w; + lin_u->tip_y = c3_malloc(len_w); // note: off-loom + lin_u->dat_y = lin_u->tip_y + tip_w; + lin_u->haz_y = lin_u->dat_y + dat_w; + memcpy(lin_u->dat_y, dat_u->fra_y, dat_u->len_w); + + c3_y* haz_y = lin_u->haz_y; + while ( pas != u3_nul ) { + u3r_bytes(0, 64, haz_y, u3h(pas)); + haz_y += 64; + pas = u3t(pas); + } + + u3r_bytes(0, tip_w, lin_u->tip_y, pof); + + mesa_free_pact(&jum_u); + } + + _mesa_put_jumbo_cache(sam_u, nam_u, lin_u); + _mesa_send_jumbo_pieces(sam_u, lin_u, NULL); + + _mesa_free_pict(pic_u); + u3z(res); + return; +} + +static void +_mesa_hear_bail(u3_ovum* egg_u, u3_noun lud) +{ + u3l_log("mesa: hear bail"); + c3_w len_w = u3qb_lent(lud); + u3l_log("len_w: %i", len_w); + if( len_w == 2 ) { + u3_pier_punt_goof("hear", u3k(u3h(lud))); + u3_pier_punt_goof("crud", u3k(u3h(u3t(lud)))); + } + u3_ovum_free(egg_u); +} + +static void +_saxo_cb(void* vod_p, u3_noun nun) +{ + u3_peer* per_u = vod_p; + u3_weak sax = u3r_at(7, nun); + + if ( sax != u3_none ) { + u3_noun her = u3do("head", u3k(sax)); + u3_peer* new_u = _mesa_get_peer_raw(per_u->sam_u, u3k(her)); + if ( new_u != NULL ) { + per_u = new_u; + } + u3_mesa* sam_u = per_u->sam_u; + u3_noun gal = u3do("rear", u3k(sax)); + u3_assert( c3y == u3a_is_cat(gal) && gal < 256 ); + // both atoms guaranteed to be cats, bc we don't call unless forwarding + per_u->ful_o = c3y; + per_u->imp_y = gal; + _mesa_put_peer_raw(per_u->sam_u, her, per_u); + } + + u3z(nun); +} + +static void +_meet_peer(u3_mesa* sam_u, u3_peer* per_u, u3_ship her_u) +{ + u3_noun her = u3_ship_to_noun(her_u); + u3_noun gan = u3nc(u3_nul, u3_nul); + u3_noun pax = u3nc(u3dc("scot", c3__p, her), u3_nul); + u3_pier_peek_last(sam_u->pir_u, gan, c3__j, c3__saxo, pax, per_u, _saxo_cb); +} + +static void +_hear_peer(u3_mesa* sam_u, u3_peer* per_u, u3_lane lan_u, c3_o dir_o) +{ + if ( c3y == dir_o ) { + per_u->dan_u = lan_u; + per_u->dir_u.her_d = _get_now_micros(); + } else { + per_u->ind_u.her_d = _get_now_micros(); + } +} + +static void +_mesa_request_next_fragments(u3_mesa* sam_u, + u3_pend_req* req_u, + u3_lane lan_u) +{ + c3_w win_w = _mesa_req_get_cwnd(req_u); + u3_mesa_pict* nex_u = req_u->pic_u; + c3_w nex_d = req_u->nex_d; + for ( int i = 0; i < win_w; i++ ) { + c3_w fra_w = nex_d + i; + if ( fra_w >= req_u->tof_d ) { + break; + } + nex_u->pac_u.pek_u.nam_u.fra_d = nex_d + i; + _mesa_add_our_to_pit(sam_u, &nex_u->pac_u.pek_u.nam_u); + _mesa_send(nex_u, &lan_u); + _mesa_req_pact_sent(req_u, &nex_u->pac_u.pek_u.nam_u); + } +} + +typedef struct _u3_mesa_veri_cb_data { + u3_mesa* sam_u; + u3_mesa_name nam_u; + u3_lane lan_u; +} u3_mesa_veri_cb_data; + +static void +_mesa_veri_scry_cb(void* vod_p, u3_noun nun) +{ + u3_mesa_veri_cb_data* ver_u = vod_p; + u3_pend_req* req_u = _mesa_get_request(ver_u->sam_u, &ver_u->nam_u); + if ( !req_u ) { + return; + } + else if ( c3y == nun ) { // XX + _mesa_request_next_fragments(ver_u->sam_u, req_u, ver_u->lan_u); + } + else if ( c3n == nun ) { + u3l_log("mesa: packet auth failed verification"); + // TODO: wipe request state? (If this was an imposter, + // we don't want to punish the real peer.) + } + else { + u3l_log("mesa: %%veri returned strange value"); + } + c3_free(ver_u->nam_u.pat_c); + c3_free(ver_u); +} + +static void +_mesa_req_pact_init(u3_mesa* sam_u, u3_mesa_pict* pic_u, u3_lane* lan_u) +{ + u3_mesa_pact* pac_u = &pic_u->pac_u; + u3_mesa_name* nam_u = &pac_u->pag_u.nam_u; + u3_mesa_data* dat_u = &pac_u->pag_u.dat_u; + + u3_gage* gag_u = _mesa_get_lane(sam_u, nam_u->her_u, lan_u); + if ( gag_u == NULL ) { + gag_u = alloca(sizeof(u3_gage)); + _init_gage(gag_u); + // save and re-retrieve so we have persistent pointer + _mesa_put_lane(sam_u, nam_u->her_u, lan_u, gag_u); + gag_u = _mesa_get_lane(sam_u, nam_u->her_u, lan_u); + u3_assert( gag_u != NULL ); + } + + u3_pend_req* req_u = alloca(sizeof(u3_pend_req)); + memset(req_u, 0, sizeof(u3_pend_req)); + req_u->pic_u = c3_calloc(sizeof(u3_mesa_pict)); + req_u->pic_u->sam_u = sam_u; + req_u->pic_u->pac_u.hed_u.typ_y = PACT_PEEK; + req_u->pic_u->pac_u.hed_u.pro_y = MESA_VER; + memcpy(&req_u->pic_u->pac_u.pek_u.nam_u, nam_u, sizeof(u3_mesa_name)); // XX + req_u->pic_u->pac_u.pek_u.nam_u.pat_c = c3_malloc(nam_u->pat_s + 1); + memcpy(req_u->pic_u->pac_u.pek_u.nam_u.pat_c, nam_u->pat_c, nam_u->pat_s + 1); + req_u->pic_u->pac_u.pek_u.nam_u.aut_o = c3n; + req_u->pic_u->pac_u.pek_u.nam_u.nit_o = c3n; + req_u->aut_u = dat_u->aut_u; + + u3_assert( pac_u->pag_u.nam_u.boq_y == 13 ); + req_u->gag_u = gag_u; + req_u->tob_d = dat_u->tob_d; + req_u->tof_d = mesa_num_leaves(dat_u->tob_d); // NOTE: only correct for bloq 13! + assert( req_u->tof_d != 1 ); // these should be injected directly by _mesa_hear_page + req_u->dat_y = c3_calloc(dat_u->tob_d); + req_u->wat_u = c3_calloc(sizeof(u3_pact_stat) * req_u->tof_d + 2 ); + bitset_init(&req_u->was_u, req_u->tof_d); + + // TODO: handle restart + // u3_assert( nam_u->fra_w == 0 ); + + req_u->nex_d = 0; + req_u->hav_d = 0; + req_u->lef_d = 0; + req_u->old_d = 0; + req_u->ack_d = 0; + + c3_w pof_w = lss_proof_size(req_u->tof_d); + lss_hash* pof_u = c3_calloc(pof_w * sizeof(lss_hash)); + if ( dat_u->len_w != pof_w*sizeof(lss_hash) ) { + return; // TODO: handle like other auth failures + } + for ( int i = 0; i < pof_w; i++ ) { + memcpy(pof_u[i], dat_u->fra_y + (i * sizeof(lss_hash)), sizeof(lss_hash)); + } + lss_hash root; + lss_root(root, pof_u, pof_w); + req_u->los_u = c3_calloc(sizeof(lss_verifier)); + lss_verifier_init(req_u->los_u, 0, req_u->tof_d, pof_u); + c3_free(pof_u); + + req_u = _mesa_put_request(sam_u, nam_u, req_u); + _update_resend_timer(req_u); + + // scry to verify auth + u3_noun typ, aut; + switch ( dat_u->aut_u.typ_e ) { + case AUTH_SIGN: + typ = c3__sign; + aut = u3dc("scot", c3__uv, u3i_bytes(64, dat_u->aut_u.sig_y)); + break; + case AUTH_HMAC: + typ = c3__hmac; + aut = u3dc("scot", c3__uv, u3i_bytes(16, dat_u->aut_u.mac_y)); + break; + default: + return; // TODO: handle like other auth failures + } + u3_noun her = u3dc("scot", c3__p, u3_ship_to_noun(nam_u->her_u)); + u3_noun rut = u3dc("scot", c3__uv, u3i_bytes(32, root)); + u3_noun pax = _mesa_encode_path(nam_u->pat_s, (c3_y*)nam_u->pat_c); + u3_noun sky = u3i_list(typ, her, aut, rut, pax, u3_none); + u3_mesa_veri_cb_data* ver_u = c3_malloc(sizeof(u3_mesa_veri_cb_data)); + ver_u->sam_u = sam_u; + memcpy(&ver_u->nam_u, nam_u, sizeof(u3_mesa_name)); + ver_u->nam_u.pat_c = c3_malloc(nam_u->pat_s + 1); + memcpy(ver_u->nam_u.pat_c, nam_u->pat_c, nam_u->pat_s + 1); + ver_u->lan_u = *lan_u; + u3_pier_peek_last(sam_u->pir_u, u3_nul, c3__a, c3__veri, sky, ver_u, _mesa_veri_scry_cb); +} + +typedef struct _u3_mesa_lane_cb_data { + u3_lane lan_u; + u3_peer* per_u; + u3_mesa_name* nam_u; +} u3_mesa_lane_cb_data; + +static void +_mesa_free_lane_cb_data(u3_mesa_lane_cb_data* dat_u) +{ + _mesa_free_name(dat_u->nam_u); + c3_free(dat_u); +} + +// TODO should put in cache on success +static void +_mesa_page_news_cb(u3_ovum* egg_u, u3_ovum_news new_e) +{ + u3_mesa_lane_cb_data* dat_u = egg_u->ptr_v; + + if ( u3_ovum_done != new_e ) { + /* + #ifdef MESA_DEBUG + u3l_log("mesa: arvo page event was not a success, %s", + (u3_ovum_drop == new_e)? "DROP" : + (u3_ovum_work == new_e)? "WORK" : "WACK" + ); + #endif + */ + return; + } + + #ifdef MESA_DEBUG + c3_c* her_c = u3_ship_to_string(dat_u->nam_u->her_u); + u3l_log("mesa: processed %%page from %s", her_c); + c3_free(her_c); + #endif + + // XX do early delete instead, to avoid injecting retries + // _mesa_del_pit(dat_u->per_u->sam_u, dat_u->nam_u); + _mesa_free_lane_cb_data(dat_u); +} + +static void +_mesa_page_bail_cb(u3_ovum* egg_u, u3_ovum_news new_e) +{ + #ifdef MESA_DEBUG + u3l_log("mesa: arvo page event failed"); + #endif + _mesa_free_lane_cb_data((u3_mesa_lane_cb_data*)egg_u->ptr_v); +} + +static void +_mesa_add_hop(c3_y hop_y, u3_mesa_head* hed_u, u3_mesa_page_pact* pag_u, u3_lane lan_u) +{ + if ( 1 == hop_y ) { + c3_etch_word(pag_u->sot_u, lan_u.pip_w); + c3_etch_short(pag_u->sot_u + 4, lan_u.por_s); + hed_u->nex_y = HOP_SHORT; + return; + } + + hed_u->nex_y = HOP_MANY; + + u3_mesa_hop_once* lan_y = c3_calloc(sizeof(u3_mesa_hop_once)); + + c3_etch_word(lan_y->dat_y, lan_u.pip_w); + c3_etch_short(lan_y->dat_y, lan_u.por_s); + + lan_y->len_w = 6; + + c3_realloc(&pag_u->man_u, pag_u->man_u.len_w + 8); + pag_u->man_u.dat_y[pag_u->man_u.len_w] = *lan_y; + + pag_u->man_u.len_w++; + +} + +static void +_mesa_hear_page(u3_mesa_pict* pic_u, u3_lane lan_u) +{ + #ifdef MESA_DEBUG + // u3l_log("mesa: hear_page()"); + // log_pact(&pic_u->pac_u); + u3_assert( PACT_PAGE == pic_u->pac_u.hed_u.typ_y ); + #endif + + u3_mesa* sam_u = pic_u->sam_u; + u3_mesa_pact* pac_u = &pic_u->pac_u; + u3_mesa_name* nam_u = &pac_u->pek_u.nam_u; + c3_s fra_s; + + c3_o our_o = u3_ships_equal(nam_u->her_u, sam_u->pir_u->who_d); + + // forwarding wrong, need a PIT entry + // if ( c3n == our_o ) { + // _mesa_forward_response(pic_u, lan_u); + // _mesa_free_pict(pic_u); + // return; + // } + + u3_peer* per_u = _mesa_get_peer(sam_u, nam_u->her_u); + c3_o new_o = c3n; + if ( NULL == per_u ) { + new_o = c3y; + per_u = c3_calloc(sizeof(u3_peer)); + _init_peer(sam_u, per_u); + _meet_peer(sam_u, per_u, nam_u->her_u); + } + + c3_o dir_o = __(pac_u->hed_u.hop_y == 0); + if ( pac_u->hed_u.hop_y == 0 ) { + _hear_peer(sam_u, per_u, lan_u, dir_o); + } else { + u3l_log(" received forwarded page"); + } + if ( new_o == c3y ) { + //u3l_log("new lane is direct %c", c3y == dir_o ? 'y' : 'n'); + //_log_lane(&lan_u); + } + + _mesa_put_peer(sam_u, nam_u->her_u, per_u); + + u3_weak pin = _mesa_get_pit(sam_u, nam_u); + + if ( u3_none == pin ) { + #ifdef MESA_DEBUG + u3l_log(" no PIT entry"); + log_name(nam_u); + #endif + _mesa_free_pict(pic_u); + return; + } + u3_noun our, las; + u3x_cell(pin, &our, &las); + if ( u3_nul != las ) { + #ifdef MESA_DEBUG + u3l_log(" forwarding"); + #endif + + inc_hopcount(&pac_u->hed_u); + c3_etch_word(pac_u->pag_u.sot_u, lan_u.pip_w); + c3_etch_short(pac_u->pag_u.sot_u + 4, lan_u.por_s); + + // stick next hop in packet + _mesa_add_hop(pac_u->hed_u.hop_y, &pac_u->hed_u ,&pac_u->pag_u, lan_u); + + _mesa_send_pact(sam_u, u3k(las), per_u, pac_u); + _mesa_del_pit(sam_u, nam_u); + _mesa_free_pict(pic_u); + u3z(pin); + return; + } + if ( c3n == our ) { + // TODO: free pact and pict + _mesa_free_pict(pic_u); + u3z(pin); + return; + } + + // process incoming response to ourselves + // TODO: memory management, maybe free pict and pact + + // if single-leaf message, inject directly into Arvo + c3_d lev_d = mesa_num_leaves(pac_u->pag_u.dat_u.tob_d); + if ( 1 == lev_d ) { + u3_noun cad; + { + u3_noun lan = u3_mesa_encode_lane(lan_u); + + // XX should just preserve input buffer + u3i_slab sab_u; + u3i_slab_init(&sab_u, 3, PACT_SIZE); + mesa_etch_pact_to_buf(sab_u.buf_y, PACT_SIZE, pac_u); + cad = u3nt(c3__heer, lan, u3i_slab_mint(&sab_u)); + } + + u3_noun wir = u3nc(c3__ames, u3_nul); + + u3_ovum* ovo = u3_ovum_init(0, c3__ames, wir, cad); + ovo = u3_auto_plan(&sam_u->car_u, ovo); + + u3_mesa_lane_cb_data* dat_u = c3_calloc(sizeof(u3_mesa_lane_cb_data)); + { + dat_u->per_u = per_u; + dat_u->lan_u.pip_w = lan_u.pip_w; + dat_u->lan_u.por_s = lan_u.por_s; + dat_u->nam_u = _mesa_copy_name_alloc(nam_u); + } + // early deletion, to avoid injecting retries, + // (in case of failure, the retry timer will add it again to the PIT) + // + _mesa_del_pit(dat_u->per_u->sam_u, dat_u->nam_u); + u3_auto_peer(ovo, dat_u, _mesa_page_news_cb, _mesa_page_bail_cb); + _mesa_free_pict(pic_u); + u3z(pin); + return; + } + + u3_pend_req* req_u = _mesa_get_request(sam_u, nam_u); + if ( !req_u ) { + if ( 0 == nam_u->fra_d ) { + _mesa_req_pact_init(sam_u, pic_u, &lan_u); + } + _mesa_del_pit(sam_u, nam_u); + _mesa_free_pict(pic_u); // XX leaks packet + u3z(pin); + return; + } + + u3_lane lon_u; + if ( HOP_SHORT == pac_u->hed_u.nex_y ) { + lon_u.pip_w = c3_sift_word(pac_u->pag_u.sot_u); + lon_u.por_s = c3_sift_short(pac_u->pag_u.sot_u + 4); + } + else { + lon_u = lan_u; + } + _mesa_req_pact_done(req_u, + nam_u, + &pac_u->pag_u.dat_u, + pac_u->hed_u.hop_y, + lon_u); + // TODO: check return value before continuing? + + c3_y boq_y = 31; + // c3_o done_with_jumbo_frame = __(0 == req_u->hav_d % boq_y); + c3_o done_with_jumbo_frame = __(req_u->hav_d == req_u->tof_d); // TODO: fix for non-message-sized jumbo frames + // _mesa_del_pit(sam_u, nam_u); XX + if ( c3y == done_with_jumbo_frame ) { + u3_noun cad; + +#ifdef U3_OS_osx + u3l_log(" received last packet, tof_d: %llu tob_d: %llu", +#else + u3l_log(" received last packet, tof_d: %lu tob_d: %lu", +#endif + req_u->tof_d, + req_u->tob_d); + c3_d now_d = _get_now_micros(); +#ifdef U3_OS_osx + u3l_log("%llu kilobytes took %f ms", +#else + u3l_log("%lu kilobytes took %f ms", +#endif + req_u->tof_d, + (now_d - sam_u->tim_d)/1000.0); + + { + // construct jumbo frame + u3_noun lan = u3_mesa_encode_lane(lan_u); + u3_noun pac; + { + pac_u->pag_u.nam_u.boq_y = boq_y; + pac_u->pag_u.dat_u.tob_d = req_u->tob_d; + pac_u->pag_u.nam_u.fra_d = (req_u->hav_d >> boq_y); + pac_u->pag_u.dat_u.len_w = req_u->tob_d; + c3_free(pac_u->pag_u.dat_u.fra_y); + pac_u->pag_u.dat_u.fra_y = req_u->dat_y; + pac_u->pag_u.dat_u.aut_u = req_u->aut_u; + + c3_y* buf_y = c3_calloc(mesa_size_pact(pac_u)); + c3_w res_w = mesa_etch_pact_to_buf(buf_y, mesa_size_pact(pac_u), pac_u); + pac = u3i_bytes(res_w, buf_y); + c3_free(buf_y); + } + cad = u3nt(c3__heer, lan, pac); + } + + _mesa_del_request(sam_u, &pac_u->pag_u.nam_u); + _mesa_free_pict(pic_u); + + u3_auto_plan(&sam_u->car_u, + u3_ovum_init(0, c3__ames, u3nc(c3__ames, u3_nul), cad)); + } else if ( req_u->hav_d < lev_d ) { + _mesa_request_next_fragments(sam_u, req_u, lan_u); + _mesa_free_pict(pic_u); + u3z(pin); + } else { + _mesa_free_pict(pic_u); + u3z(pin); + } + +} + +static void +_mesa_forward_request(u3_mesa* sam_u, u3_mesa_pict* pic_u, u3_lane lan_u) +{ + u3_mesa_pact* pac_u = &pic_u->pac_u; + u3_peer* per_u = _mesa_get_peer(sam_u, pac_u->pek_u.nam_u.her_u); + if ( !per_u ) { + #ifdef MESA_DEBUG + c3_c* mes = u3_ship_to_string(pac_u->pek_u.nam_u.her_u); + u3l_log("mesa: alien forward for %s", mes); + c3_free(mes); + #endif + _mesa_free_pict(pic_u); + return; + } + if ( c3y == sam_u->for_o && sam_u->pir_u->who_d[0] == per_u->imp_y ) { + u3_lane lin_u = _mesa_get_direct_lane(sam_u, pac_u->pek_u.nam_u.her_u); + u3_lane zer_u = {0, 0}; + if ( _mesa_lanes_equal(&zer_u, &lin_u) == c3y) { + _mesa_free_pict(pic_u); + return; + } + inc_hopcount(&pac_u->hed_u); + #ifdef MESA_DEBUG + u3l_log("mesa: forward_request()"); + log_pact(pac_u); + #endif + _mesa_add_lane_to_pit(sam_u, &pac_u->pek_u.nam_u, lan_u); + _mesa_send(pic_u, &lin_u); + } + _mesa_free_pict(pic_u); +} + +static void +_mesa_hear_peek(u3_mesa_pict* pic_u, u3_lane lan_u) +{ + #ifdef MESA_DEBUG + // u3l_log("mesa: hear_peek()"); + u3_assert( PACT_PEEK == pic_u->pac_u.hed_u.typ_y ); + #endif + + u3_mesa_pact* pac_u = &pic_u->pac_u; + u3_mesa* sam_u = pic_u->sam_u; + c3_o our_o = u3_ships_equal(pac_u->pek_u.nam_u.her_u, sam_u->pir_u->who_d); + + if ( c3n == our_o ) { + _mesa_forward_request(sam_u, pic_u, lan_u); + return; + } + // record interest + _mesa_add_lane_to_pit(sam_u, &pac_u->pek_u.nam_u, lan_u); + + c3_d fra_d = pac_u->pek_u.nam_u.fra_d; + c3_d bat_d = _mesa_lop(fra_d); + + pac_u->pek_u.nam_u.fra_d = bat_d; + + // if we have the page, send it + u3_mesa_line* lin_u = _mesa_get_jumbo_cache(sam_u, &pac_u->pek_u.nam_u); + if ( ( NULL != lin_u ) && ( CTAG_ITEM == lin_u->typ_y )) { + _mesa_send_jumbo_pieces(sam_u, lin_u, &fra_d); + _mesa_free_pict(pic_u); + return; + } + + // if we are waiting, no-op + if ( ( NULL != lin_u ) && ( CTAG_WAIT == lin_u->typ_y )) { + _mesa_free_pict(pic_u); + return; + } + + if ( NULL == lin_u ) { u3l_log("lin_u NULL"); } + + // otherwise, if blocked or NULL scry + lin_u = c3_calloc(sizeof(u3_mesa_line)); + lin_u->typ_y = CTAG_WAIT; + _mesa_copy_name(&lin_u->nam_u, &pac_u->pek_u.nam_u); // XX + + _mesa_put_jumbo_cache(sam_u, &pac_u->pek_u.nam_u, lin_u); + u3_noun sky = _name_to_jumbo_scry(&pac_u->pek_u.nam_u); + u3_noun our = u3i_chubs(2, sam_u->car_u.pir_u->who_d); + u3_noun bem = u3nc(u3nt(our, u3_nul, u3nc(c3__ud, 1)), sky); + + u3_pier_peek(sam_u->car_u.pir_u, u3_nul, u3k(u3nq(1, c3__beam, c3__ax, bem)), pic_u, _mesa_page_scry_jumbo_cb); +} + +static void +_mesa_poke_news_cb(u3_ovum* egg_u, u3_ovum_news new_e) +{ + if ( u3_ovum_done != new_e ) { + return; + } + u3_mesa_lane_cb_data* dat_u = egg_u->ptr_v; + u3l_log("free(dat_u) in poke_news_cb"); + _mesa_free_lane_cb_data(dat_u); +} + +static void +_mesa_poke_bail_cb(u3_ovum* egg_u, u3_noun lud) +{ + u3_mesa_lane_cb_data* dat_u = egg_u->ptr_v; + // XX failure stuff here + u3l_log("mesa: poke failure"); + _mesa_free_lane_cb_data(dat_u); +} + +static void +_mesa_hear_poke(u3_mesa_pict* pic_u, u3_lane* lan_u) +{ + u3_mesa_pact* pac_u = &pic_u->pac_u; + u3_mesa* sam_u = pic_u->sam_u; + + #ifdef MESA_DEBUG + u3l_log("mesa: hear_poke()"); + u3_assert( PACT_POKE == pac_u->hed_u.typ_y ); + #endif + + c3_o our_o = u3_ships_equal(pac_u->pek_u.nam_u.her_u, sam_u->pir_u->who_d); + + if ( c3n == our_o ) { + _mesa_forward_request(sam_u, pic_u, *lan_u); + return; + } + // TODO check if lane already in pit, drop dupes + _mesa_add_lane_to_pit(sam_u, &pac_u->pek_u.nam_u, *lan_u); + + // XX if this lane management stuff is necessary + // it should be deferred to after successful event processing + u3_peer* per_u = _mesa_get_peer(sam_u, pac_u->pok_u.pay_u.her_u); + c3_o new_o = c3n; + if ( NULL == per_u ) { + new_o = c3y; + per_u = c3_calloc(sizeof(u3_peer)); + _init_peer(sam_u, per_u); + _meet_peer(sam_u, per_u, pac_u->pok_u.pay_u.her_u); + } + + c3_o dir_o = __(pac_u->hed_u.hop_y == 0); + if ( pac_u->hed_u.hop_y == 0 ) { + new_o = c3y; + _hear_peer(sam_u, per_u, *lan_u, dir_o); + // u3l_log("learnt lane"); + } else { + // u3l_log("received forwarded poke"); + } + if ( new_o == c3y ) { + // u3l_log("new lane is direct %c", c3y == dir_o ? 'y' : 'n'); + // _log_lane(lan_u); + } + _mesa_put_peer(sam_u, pac_u->pok_u.pay_u.her_u, per_u); + + u3_ovum_peer nes_f; + u3_ovum_bail bal_f; + void* ptr_v; + + u3_noun wir = u3nc(c3__ames, u3_nul); + u3_noun cad; + { + u3_noun lan = u3_mesa_encode_lane(*lan_u); + u3i_slab sab_u; + u3i_slab_init(&sab_u, 3, PACT_SIZE); + + // XX should just preserve input buffer + mesa_etch_pact_to_buf(sab_u.buf_y, PACT_SIZE, pac_u); + cad = u3nt(c3__heer, lan, u3i_slab_mint(&sab_u)); + } + + u3_ovum* ovo = u3_ovum_init(0, c3__ames, wir, cad); + ovo = u3_auto_plan(&sam_u->car_u, ovo); + + // XX check request state for *payload* (in-progress duplicate) + assert(pac_u->pok_u.dat_u.tob_d); + u3_mesa_lane_cb_data* dat_u = c3_malloc(sizeof(u3_mesa_lane_cb_data)); + { + dat_u->nam_u = c3_malloc(sizeof(u3_mesa_name)); + memcpy(dat_u->nam_u, &pac_u->pek_u.nam_u, sizeof(u3_mesa_name)); + dat_u->nam_u->pat_c = c3_malloc(pac_u->pek_u.nam_u.pat_s + 1); + memcpy(dat_u->nam_u->pat_c, pac_u->pek_u.nam_u.pat_c, pac_u->pek_u.nam_u.pat_s + 1); + dat_u->lan_u.pip_w = lan_u->pip_w; + dat_u->lan_u.por_s = lan_u->por_s; + dat_u->per_u = per_u; + } + u3_auto_peer(ovo, dat_u, _mesa_poke_news_cb, _mesa_poke_bail_cb); + _mesa_free_pict(pic_u); +} + +void +_ames_hear(void* sam_u, + const struct sockaddr* adr_u, + c3_w len_w, + c3_y* hun_y); + +static void +_mesa_hear(u3_mesa* sam_u, + const struct sockaddr* adr_u, + c3_w len_w, + c3_y* hun_y) +{ + if ( c3n == mesa_is_new_pact(hun_y, len_w) ) { + u3l_log("mesa: old hear"); + _ames_hear(u3_Host.sam_u, adr_u, len_w, hun_y); + return; + } + + u3_mesa_pict* pic_u = c3_calloc(sizeof(u3_mesa_pict)); + pic_u->sam_u = sam_u; + c3_c* err_c = mesa_sift_pact_from_buf(&pic_u->pac_u, hun_y, len_w); + if ( err_c ) { + u3l_log("mesa: hear: sift failed: %s", err_c); + _mesa_free_pict(pic_u); + return; + } + c3_free(hun_y); + + struct sockaddr_in* add_u = (struct sockaddr_in*)adr_u; + u3_lane lan_u; + + lan_u.por_s = ntohs(add_u->sin_port); + lan_u.pip_w = ntohl(add_u->sin_addr.s_addr); + + + switch ( pic_u->pac_u.hed_u.typ_y ) { + case PACT_PEEK: { + _mesa_hear_peek(pic_u, lan_u); + } break; + case PACT_PAGE: { + _mesa_hear_page(pic_u, lan_u); + } break; + default: { + _mesa_hear_poke(pic_u, &lan_u); + } break; + } +} + +static void _mesa_recv_cb(uv_udp_t* wax_u, + ssize_t nrd_i, + const uv_buf_t * buf_u, + const struct sockaddr* adr_u, + unsigned flg_i) +{ + if ( 0 > nrd_i ) { + if ( u3C.wag_w & u3o_verbose ) { + u3l_log("mesa: recv: fail: %s", uv_strerror(nrd_i)); + } + c3_free(buf_u->base); + } + else if ( 0 == nrd_i ) { + c3_free(buf_u->base); + } + else if ( flg_i & UV_UDP_PARTIAL ) { + if ( u3C.wag_w & u3o_verbose ) { + u3l_log("mesa: recv: fail: message truncated"); + } + c3_free(buf_u->base); + } + else { + _mesa_hear(wax_u->data, adr_u, (c3_w)nrd_i, (c3_y*)buf_u->base); + } +} + +static void +_mesa_io_talk(u3_auto* car_u) +{ + u3_mesa* sam_u = (u3_mesa*)car_u; + sam_u->dns_c = "urbit.org"; // TODO: receive turf + { + // XX remove [sev_l] + // + u3_noun wir = u3nt(c3__ames, + u3dc("scot", c3__uv, sam_u->sev_l), + u3_nul); + u3_noun cad = u3nc(c3__born, u3_nul); + + u3_auto_plan(car_u, u3_ovum_init(0, c3__a, wir, cad)); + } + u3_noun who = u3i_chubs(2, sam_u->pir_u->who_d); + u3_noun rac = u3do("clan:title", u3k(who)); + c3_s por_s = sam_u->pir_u->por_s; + c3_i ret_i; + if ( c3__czar == rac ) { + c3_y num_y = (c3_y)sam_u->pir_u->who_d[0]; + c3_s zar_s = _ames_czar_port(num_y); + + if ( 0 == por_s ) { + por_s = zar_s; + } + else if ( por_s != zar_s ) { + u3l_log("ames: czar: overriding port %d with -p %d", zar_s, por_s); + u3l_log("ames: czar: WARNING: %d required for discoverability", zar_s); + } + } + + + // Bind and stuff. + { + struct sockaddr_in add_u; + c3_i add_i = sizeof(add_u); + + memset(&add_u, 0, sizeof(add_u)); + add_u.sin_family = AF_INET; + add_u.sin_addr.s_addr = _(u3_Host.ops_u.net) ? + htonl(INADDR_ANY) : + htonl(INADDR_LOOPBACK); + add_u.sin_port = htons(por_s); + + if ( (ret_i = uv_udp_bind(&u3_Host.wax_u, + (const struct sockaddr*)&add_u, 0)) != 0 ) + { + u3l_log("mesa: bind: %s", uv_strerror(ret_i)); + + /*if ( (c3__czar == rac) && + (UV_EADDRINUSE == ret_i) ) + { + u3l_log(" ...perhaps you've got two copies of vere running?"); + }*/ + + // XX revise + // + u3_pier_bail(u3_king_stub()); + } + + uv_udp_getsockname(&u3_Host.wax_u, (struct sockaddr *)&add_u, &add_i); + u3_assert(add_u.sin_port); + + sam_u->pir_u->por_s = ntohs(add_u.sin_port); + } + if ( c3y == u3_Host.ops_u.net ) { + u3l_log("mesa: live on %d", sam_u->pir_u->por_s); + } + else { + u3l_log("mesa: live on %d (localhost only)", sam_u->pir_u->por_s); + } + + u3_Host.wax_u.data = sam_u; + uv_udp_recv_start(&u3_Host.wax_u, _ames_alloc, _mesa_recv_cb); + + sam_u->car_u.liv_o = c3y; + //u3z(rac); u3z(who); +} + +/* _mesa_io_init(): initialize ames I/O. +*/ +u3_auto* +u3_mesa_io_init(u3_pier* pir_u) +{ + u3l_log("mesa: INIT"); + u3_mesa* sam_u = c3_calloc(sizeof(*sam_u)); + sam_u->pir_u = pir_u; + + // XX tune cache sizes + sam_u->her_p = u3h_new_cache(100000); + sam_u->lan_p = u3h_new_cache(100000); + sam_u->pac_p = u3h_new_cache(10000); + sam_u->pit_p = u3h_new_cache(1000000); + + u3_assert( !uv_udp_init(u3L, &sam_u->wax_u) ); + sam_u->wax_u.data = sam_u; + + sam_u->sil_u = u3s_cue_xeno_init(); + sam_u->tes_u = ur_cue_test_init(); + + // Disable networking for fake ships + // + if ( c3y == sam_u->pir_u->fak_o ) { + u3_Host.ops_u.net = c3n; + } + + sam_u->for_o = c3n; + { + u3_noun her = u3i_chubs(2, pir_u->who_d); + for (int i = 0; i < 256; i++) { + sam_u->imp_u[i].pen = u3_nul; + sam_u->imp_u[i].sam_u = sam_u; + sam_u->imp_u[i].imp_y = i; + //sam_u.imp_u[i].tim = 0; + if ( u3_Host.ops_u.net == c3n ) { + sam_u->imp_u[i].pip_w = 0x7f000001; + } else { + sam_u->imp_u[i].pip_w = 0; + } + } + + if ( c3y == u3a_is_cat(her) && her < 256 ) { + u3l_log("mesa: forwarding enabled"); + sam_u->for_o = c3y; + } + u3z(her); + } + + + u3_auto* car_u = &sam_u->car_u; + car_u->nam_m = c3__ames; + car_u->liv_o = c3y; + car_u->io.talk_f = _mesa_io_talk; + car_u->io.info_f = _mesa_io_info; + car_u->io.slog_f = _mesa_io_slog; + car_u->io.kick_f = _mesa_io_kick; + car_u->io.exit_f = _mesa_io_exit; + + + + /*{ + u3_noun now; + struct timeval tim_u; + gettimeofday(&tim_u, 0); + + now = u3_time_in_tv(&tim_u); + //sam_u->sev_l = u3r_mug(now); + u3z(now); + }*/ + + return car_u; +} + diff --git a/pkg/vere/io/mesa/bitset.c b/pkg/vere/io/mesa/bitset.c new file mode 100644 index 0000000000..22f687b25b --- /dev/null +++ b/pkg/vere/io/mesa/bitset.c @@ -0,0 +1,131 @@ +#include "bitset.h" +#include + +#include "vere.h" + +void bitset_init(u3_bitset* bit_u, c3_w len_w) +{ + bit_u->len_w = len_w; + bit_u->buf_y = c3_calloc((len_w >> 3) + 1); +} + +void +bitset_free(u3_bitset* bit_u) +{ + c3_free(bit_u->buf_y); +} + +static c3_y +_popcnt(c3_y num_y) +{ + return __builtin_popcount(num_y); +} + +static void +_log_bitset(u3_bitset* bit_u) +{ + c3_w cur_w = 0; + while( cur_w < bit_u->len_w ) { + if ( c3y == bitset_has(bit_u, cur_w) ) { + u3l_log("%u", cur_w); + } + cur_w++; + } +} + +c3_w +bitset_wyt(u3_bitset* bit_u) +{ + c3_w ret_w = 0; + c3_w len_w = (bit_u->len_w >> 3); + for(int i = 0; i < len_w; i++ ) { + ret_w += _popcnt(bit_u->buf_y[i]); + } + return ret_w; +} + +void bitset_put(u3_bitset* bit_u, c3_w mem_w) +{ + if (( mem_w > bit_u->len_w )) { + u3l_log("overrun %u, %u", mem_w, bit_u->len_w); + return; + } + c3_w idx_w = mem_w >> 3; + c3_w byt_y = bit_u->buf_y[idx_w]; + c3_y rem_y = mem_w & 0x7; + c3_y mas_y = (1 << rem_y); + bit_u->buf_y[idx_w] = byt_y | mas_y; +} + +c3_o +bitset_has(u3_bitset* bit_u, c3_w mem_w) { + if (( mem_w > bit_u->len_w )) { + u3l_log("overrun %u, %u", mem_w, bit_u->len_w); + return c3n; + } + + u3_assert( mem_w < bit_u->len_w ); + c3_w idx_w = mem_w >> 3; + c3_y rem_y = mem_w & 0x7; + return __( (bit_u->buf_y[idx_w] >> rem_y) & 0x1); +} + +void +bitset_del(u3_bitset* bit_u, c3_w mem_w) +{ + u3_assert( mem_w < bit_u->len_w ); + c3_w idx_w = mem_w >> 3; + c3_w byt_y = bit_u->buf_y[idx_w]; + c3_y rem_y = mem_w & 0x7; + c3_y mas_y = ~(1 << rem_y); + bit_u->buf_y[idx_w] &= mas_y; +} + + + + +#ifdef BITSET_TEST +c3_w main() +{ + u3_bitset bit_u; + bitset_init(&bit_u, 500); + + bitset_put(&bit_u, 5); + bitset_put(&bit_u, 50); + bitset_put(&bit_u, 100); + + c3_w wyt_w = bitset_wyt(&bit_u); + if ( 3 != wyt_w ) { + u3l_log("wyt failed have %u expect %u", wyt_w, 3); + exit(1); + } + + if ( c3y == bitset_has(&bit_u, 3) ) { + u3l_log("false positive for has_bitset"); + exit(1); + } + + if ( c3n == bitset_has(&bit_u, 50) ) { + u3l_log("false negative for has_bitset"); + exit(1); + } + + bitset_del(&bit_u, 50); + + if ( c3y == bitset_has(&bit_u, 50) ) { + u3l_log("false positive for has_bitset"); + exit(1); + } + + wyt_w = bitset_wyt(&bit_u); + + if ( 2 != wyt_w ) { + u3l_log("wyt failed have %u expect %u", wyt_w, 2); + exit(1); + } + return 0; +} + +#endif + + diff --git a/pkg/vere/io/mesa/bitset.h b/pkg/vere/io/mesa/bitset.h new file mode 100644 index 0000000000..ab51dd14a8 --- /dev/null +++ b/pkg/vere/io/mesa/bitset.h @@ -0,0 +1,23 @@ +#ifndef VERE_BITSET_H +#define VERE_BITSET_H + +#include "c3/c3.h" + +typedef struct _u3_bitset { + c3_w len_w; + c3_y* buf_y; +} u3_bitset; + +void bitset_init(u3_bitset* bit_u, c3_w len_w); + +void bitset_free(u3_bitset* bit_u); + +c3_w bitset_wyt(u3_bitset* bit_u); + +void bitset_put(u3_bitset* bit_u, c3_w mem_w); + +c3_o bitset_has(u3_bitset* bit_u, c3_w mem_w); + +void bitset_del(u3_bitset* bit_u, c3_w mem_w); + +#endif diff --git a/pkg/vere/io/mesa/mesa.h b/pkg/vere/io/mesa/mesa.h new file mode 100644 index 0000000000..02e08243ae --- /dev/null +++ b/pkg/vere/io/mesa/mesa.h @@ -0,0 +1,159 @@ +#ifndef VERE_MESA_H +#define VERE_MESA_H + +#include "c3/c3.h" +#include "ship.h" + +#define MESA_VER 1 +#define FINE_PAGE 4096 // packets per page +#define FINE_FRAG 1024 // bytes per fragment packet +#define FINE_PATH_MAX 384 // longest allowed scry path +#define HEAD_SIZE 4 // header size in bytes +#define PACT_SIZE 1472 + +static c3_w MESA_COOKIE = 0x51ad1d5e; + +typedef enum _u3_mesa_ptag { + PACT_RESV = 0, + PACT_PAGE = 1, + PACT_PEEK = 2, + PACT_POKE = 3, +} u3_mesa_ptag; + +typedef enum _u3_mesa_rout_tag { + ROUT_GALAXY = 0, + ROUT_OTHER = 1 +} u3_mesa_rout_tag; + +typedef enum _u3_mesa_hop_type { + HOP_NONE = 0, + HOP_SHORT = 1, + HOP_LONG = 2, + HOP_MANY = 3 +} u3_mesa_hop_type; + +typedef struct _u3_mesa_name_meta { + c3_y ran_y; // rank (2 bits) + c3_y rif_y; // rift-len (2 bits) + c3_y nit_y; // initial overlay (1 bit) + c3_y tau_y; // %data (0) or %auth (1), 0 if !nit_o (1 bit) + c3_y gaf_y; // fragment number length (2bit) +} u3_mesa_name_meta; + +typedef struct _u3_mesa_name { + // u3_mesa_name_meta met_u; + u3_ship her_u; + c3_w rif_w; + c3_y boq_y; + c3_o nit_o; + c3_o aut_o; + c3_d fra_d; + c3_s pat_s; + c3_c* pat_c; +} u3_mesa_name; + +typedef struct _u3_mesa_data_meta { + c3_y bot_y; // total-fragments len (2 bits) + c3_o aut_o; // auth tag (c3y for message, c3n for pair) + c3_o auv_o; // auth value (c3y for sig/no-pair, c3n for hmac/pair) + c3_y men_y; // fragment length/type (2 bits) +} u3_mesa_data_meta; + +typedef enum { + AUTH_SIGN = 0, + AUTH_HMAC = 1, + AUTH_NONE = 2, + AUTH_PAIR = 3, +} u3_mesa_auth_type; + +typedef struct _u3_auth_data { + u3_mesa_auth_type typ_e; // none, traversal (none), sig, or hmac + union { // + c3_y sig_y[64]; // signature + c3_y mac_y[16]; // hmac + c3_y has_y[2][32]; // hashes + }; +} u3_auth_data; + +typedef struct _u3_mesa_data { + c3_d tob_d; // total bytes in message + u3_auth_data aut_u; // authentication + c3_w len_w; // fragment length + c3_y* fra_y; // fragment +} u3_mesa_data; + + +typedef struct _u3_mesa_head { + u3_mesa_hop_type nex_y; // next-hop + c3_y pro_y; // protocol version + u3_mesa_ptag typ_y; // packet type + c3_y hop_y; // hopcount + c3_w mug_w; // truncated mug checksum +} u3_mesa_head; + +// +// +$ cache +// [%rout lanes=(list lanes)] +// [%pending pacs=(list pact)] + + +typedef struct _u3_mesa_peek_pact { + u3_mesa_name nam_u; +} u3_mesa_peek_pact; + +typedef struct _u3_mesa_hop_once { + c3_w len_w; + c3_y* dat_y; +} u3_mesa_hop_once; + +typedef struct _u3_mesa_hop_more { + c3_w len_w; + u3_mesa_hop_once* dat_y; +} u3_mesa_hop_more; + +typedef union { + c3_y sot_u[6]; + u3_mesa_hop_once one_u; + u3_mesa_hop_more man_u; +} u3_mesa_hop; + +typedef struct _u3_mesa_page_pact { + u3_mesa_name nam_u; + u3_mesa_data dat_u; + union { + c3_y sot_u[6]; + u3_mesa_hop_once one_u; + u3_mesa_hop_more man_u; + }; +} u3_mesa_page_pact; + +typedef struct _u3_mesa_poke_pact { + u3_mesa_name nam_u; + u3_mesa_name pay_u; + u3_mesa_data dat_u; +} u3_mesa_poke_pact; + +typedef struct _u3_mesa_pact { + u3_mesa_head hed_u; + union { + u3_mesa_poke_pact pok_u; + u3_mesa_page_pact pag_u; + u3_mesa_peek_pact pek_u; + }; +} u3_mesa_pact; + +c3_d mesa_num_leaves(c3_d tot_d); +c3_w mesa_size_pact(u3_mesa_pact* pac_u); +c3_o mesa_is_new_pact(c3_y* buf_y, c3_w len_w); + +void mesa_free_pact(u3_mesa_pact* pac_u); + +c3_w mesa_etch_pact_to_buf(c3_y* buf_y, c3_w cap_w, u3_mesa_pact *pac_u); +c3_c* mesa_sift_pact_from_buf(u3_mesa_pact *pac_u, c3_y* buf_y, c3_w len_w); + +void inc_hopcount(u3_mesa_head*); + +void log_pact(u3_mesa_pact* pac_u); +void log_name(u3_mesa_name* nam_u); + +#endif diff --git a/pkg/vere/io/mesa/pact.c b/pkg/vere/io/mesa/pact.c new file mode 100644 index 0000000000..5d2eaf0b6e --- /dev/null +++ b/pkg/vere/io/mesa/pact.c @@ -0,0 +1,1633 @@ +#include "mesa.h" +#include +#include +#include +// only need for tests, can remove +#include "vere.h" +#include "ivory.h" +#include "ur/ur.h" +#include "ship.h" +#define RED_TEXT "\033[0;31m" +#define DEF_TEXT "\033[0m" +// endif tests + +#define safe_dec(num) (num == 0 ? num : num - 1) +#define _mesa_met3_w(a_w) ((c3_bits_word(a_w) + 0x7) >> 3) + +// assertions for roundtrip tests +#define MESA_ROUNDTRIP c3y +#define _assert_eq_f(a, b) \ + if ( a != b ) { \ + u3l_log("mesa.c:%u %s != %s", __LINE__, \ + __(a)? "&" : "|", \ + __(b)? "&" : "|"); \ + u3m_bail(c3__oops); \ + } +#define _assert_eq_udF(a, b) \ + if ( a != b ) { \ + u3l_log("mesa.c:%u %u != %u", __LINE__, a, b); \ + u3m_bail(c3__oops); \ + } + +#define _assert_eq_udG(a, b) \ + if ( a != b ) { \ + u3l_log("mesa.c:%u %"PRIu64" != %"PRIu64, __LINE__, a, b); \ + u3m_bail(c3__oops); \ + } + +#define _assert_eq_uxF(a, b) \ + if ( a != b ) { \ + u3l_log("mesa.c: %u 0x%08x != 0x%08x", __LINE__, a, b); \ + u3m_bail(c3__oops); \ + } + +#define _assert_eq_uxG(a, b) \ + if ( a != b ) { \ + u3l_log("mesa.c: %u 0x%016llx != 0x%016llx", __LINE__, a, b); \ + u3m_bail(c3__oops); \ + } + +static void +_mesa_check_heads_equal(u3_mesa_head* hed_u, u3_mesa_head* hod_u) +{ + _assert_eq_udF(hed_u->hop_y, hed_u->hop_y); + _assert_eq_uxF(hed_u->mug_w, hed_u->mug_w); + _assert_eq_udF(hed_u->nex_y, hed_u->nex_y); + _assert_eq_udF(hed_u->pro_y, hed_u->pro_y); + _assert_eq_udF(hed_u->typ_y, hed_u->typ_y); +} + +static void +_mesa_check_names_equal(u3_mesa_name* nam_u, u3_mesa_name* nom_u) +{ + u3_assert( __(u3_ships_equal(nam_u->her_u, nom_u->her_u)) ); + _assert_eq_udF(nam_u->rif_w, nom_u->rif_w); + _assert_eq_udF(nam_u->boq_y, nom_u->boq_y); + _assert_eq_f(nam_u->nit_o, nom_u->nit_o); + _assert_eq_f(nam_u->aut_o, nom_u->aut_o); + _assert_eq_udG(nam_u->fra_d, nom_u->fra_d); + _assert_eq_udF(nam_u->pat_s, nom_u->pat_s); + u3_assert( 0 == memcmp(nam_u->pat_c, nom_u->pat_c, nam_u->pat_s + 1) ); +} + +static void +_mesa_check_auth_datas_equal(u3_auth_data* aut_u, u3_auth_data* aot_u) +{ + _assert_eq_udF(aut_u->typ_e, aot_u->typ_e); + switch ( aut_u->typ_e ) { + case AUTH_SIGN: { + u3_assert( 0 == memcmp(aut_u->sig_y, aot_u->sig_y, 64) ); + } break; + case AUTH_HMAC: { + u3_assert( 0 == memcmp(aut_u->mac_y, aot_u->mac_y, 16) ); + } break; + case AUTH_NONE: {} break; + case AUTH_PAIR: { + u3_assert( 0 == memcmp(aut_u->has_y, aot_u->has_y, 64) ); + } break; + default: u3_assert(!"unreachable"); + } +} + +static void +_mesa_check_datas_equal(u3_mesa_data* dat_u, u3_mesa_data* dot_u) +{ + _assert_eq_udG(dat_u->tob_d, dot_u->tob_d); + _mesa_check_auth_datas_equal(&dat_u->aut_u, &dot_u->aut_u); + _assert_eq_udF(dat_u->len_w, dot_u->len_w); + u3_assert( 0 == memcmp(dat_u->fra_y, dot_u->fra_y, dat_u->len_w) ); +} + +static void +_mesa_check_pacts_equal(u3_mesa_pact* pac_u, u3_mesa_pact* poc_u) +{ + _mesa_check_heads_equal(&poc_u->hed_u, &pac_u->hed_u); + + switch ( poc_u->hed_u.typ_y ) { + case PACT_PEEK: { + _mesa_check_names_equal(&poc_u->pek_u.nam_u, &pac_u->pek_u.nam_u); + } break; + case PACT_POKE: { + _mesa_check_names_equal(&poc_u->pok_u.nam_u, &pac_u->pok_u.nam_u); + _mesa_check_names_equal(&poc_u->pok_u.pay_u, &pac_u->pok_u.pay_u); + _mesa_check_datas_equal(&poc_u->pok_u.dat_u, &pac_u->pok_u.dat_u); + } break; + case PACT_PAGE: { + _mesa_check_names_equal(&poc_u->pag_u.nam_u, &pac_u->pag_u.nam_u); + _mesa_check_datas_equal(&poc_u->pag_u.dat_u, &pac_u->pag_u.dat_u); + } break; + default: u3_assert(!"unreachable"); + } +} + +/* Logging functions +*/ + +static void +_log_head(u3_mesa_head* hed_u) +{ + u3l_log("-- HEADER --"); + u3l_log("next hop: %u", hed_u->nex_y); + u3l_log("protocol: %u", hed_u->pro_y); + u3l_log("packet type: %u", hed_u->typ_y); + u3l_log("mug: 0x%05x", (hed_u->mug_w & 0xFFFFF)); + u3l_log("hopcount: %u", hed_u->hop_y); + u3l_log(""); +} + +static void +_log_buf(c3_y* buf_y, c3_w len_w) +{ + c3_c *buf_c = c3_malloc(2 * len_w + 1); + for ( c3_w i_w = 0; i_w < len_w; i_w++ ) { + sprintf(buf_c + (i_w*2), "%02x", buf_y[i_w]); + } + u3l_log("%s", buf_c); +} + +static void +_log_name_meta(u3_mesa_name_meta* met_u) +{ + u3l_log("meta"); + u3l_log("rank: %u", met_u->ran_y); + u3l_log("rift length: %u", met_u->rif_y); + u3l_log("nit: %u", met_u->nit_y); + u3l_log("tau: %u", met_u->tau_y); + u3l_log("frag num length: %u", met_u->gaf_y); +} + +void +log_name(u3_mesa_name* nam_u) +{ + c3_c* her_c; + { + u3_noun her = u3dc("scot", c3__p, u3_ship_to_noun(nam_u->her_u)); + her_c = u3r_string(her); + u3z(her); + } + + u3l_log("%s: /%s", her_c, nam_u->pat_c); + u3l_log(" rift: %u bloq: %u auth/data: %s init: %s frag: %"PRIu64, + nam_u->rif_w, + nam_u->boq_y, + (c3y == nam_u->aut_o) ? "auth" : "data", + (c3y == nam_u->nit_o) ? "init" : "nope", + nam_u->fra_d + ); + c3_free(her_c); + fflush(stderr); +} + +static void +_log_data(u3_mesa_data* dat_u) +{ + u3l_log("tob_d: %" PRIu64 " len_w: %u ", + dat_u->tob_d, dat_u->len_w); + + switch ( dat_u->aut_u.typ_e ) { + case AUTH_SIGN: { + u3l_log("signature: "); + _log_buf(dat_u->aut_u.sig_y, 64); + } break; + + case AUTH_HMAC: { + u3l_log("hmac: "); + _log_buf(dat_u->aut_u.mac_y, 16); + } break; + + case AUTH_NONE: { + u3l_log("merkle traversal: "); + } break; + + case AUTH_PAIR: { + u3l_log("merkle traversal:"); + _log_buf(dat_u->aut_u.has_y[0], 32); + _log_buf(dat_u->aut_u.has_y[1], 32); + } break; + } +} + + +static void +_log_peek_pact(u3_mesa_peek_pact* pac_u) +{ + log_name(&pac_u->nam_u); +} + +static void +_log_page_pact(u3_mesa_page_pact *pac_u) +{ + log_name(&pac_u->nam_u); + _log_data(&pac_u->dat_u); +} + +static void +_log_poke_pact(u3_mesa_poke_pact *pac_u) +{ + log_name(&pac_u->nam_u); + log_name(&pac_u->pay_u); + _log_data(&pac_u->dat_u); +} + +void +log_pact(u3_mesa_pact* pac_u) +{ + switch ( pac_u->hed_u.typ_y ) { + case PACT_PEEK: { + fprintf(stderr, "PEEK "); + _log_peek_pact(&pac_u->pek_u); + } break; + + case PACT_PAGE: { + fprintf(stderr, "PAGE "); + _log_page_pact(&pac_u->pag_u); + } break; + + case PACT_POKE: { + fprintf(stderr, "POKE "); + _log_poke_pact(&pac_u->pok_u); + } break; + + default: { + _log_poke_pact(&pac_u->pok_u); + break; + } + } +} + +/* Helper utilities +*/ + +/* mesa_num_leaves(): calculate how many leaves, given total bytes +*/ +c3_d +mesa_num_leaves(c3_d tob_d) +{ + return (tob_d + 1023) / 1024; +} + +void +inc_hopcount(u3_mesa_head* hed_u) +{ + hed_u->hop_y = c3_min(hed_u->hop_y+1, 7); +} + +static c3_y +_mesa_rank(u3_ship who_u) +{ + switch ( u3_ship_rank(who_u) ) { + case c3__pawn: return 3; + case c3__earl: return 2; + case c3__duke: return 1; + case c3__king: return 0; + case c3__czar: return 0; + default: u3_assert(!"unreachable"); + }; +} + +/* +** _mesa_make_chub_tag(): make a 2-bit tag for a chub length +*/ +static c3_y +_mesa_make_chub_tag(c3_d tot_d) +{ + return (tot_d <= 0xff)? 0b00 : + (tot_d <= 0xffff)? 0b01 : + (tot_d <= 0xffffff)? 0b10 : + 0b11; +} + +/* +** _mesa_bytes_of_chub_tag(): how many bytes does a chub tag mean +*/ +static c3_y +_mesa_bytes_of_chub_tag(c3_y tot_y) +{ + return 1 << tot_y; +} + +/* lifecycle +*/ + +/* mesa_free_pact(): free contents of packet. +* Does *not* free pac_u itself +*/ +void mesa_free_pact(u3_mesa_pact* pac_u) +{ + c3_free(pac_u->pek_u.nam_u.pat_c); + switch ( pac_u->hed_u.typ_y ) { + default: { + break; + }; + case PACT_PEEK: { + break; + }; + case PACT_PAGE: { + c3_free(pac_u->pag_u.dat_u.fra_y); + break; + }; + case PACT_POKE: { + /* c3_free(pac_u->pok_u.nam_u.pat_c); */ + c3_free(pac_u->pok_u.pay_u.pat_c); + c3_free(pac_u->pok_u.dat_u.fra_y); + break; + }; + } +} + +/* serialisation +*/ + +typedef struct _u3_etcher { + c3_y* buf_y; + c3_w len_w; + c3_w cap_w; + c3_d bit_d; // for _etch_bits + c3_y off_y; // for _etch_bits +} u3_etcher; + +typedef struct _u3_sifter { + c3_y* buf_y; + c3_w rem_w; + c3_d bit_d; // for _etch_bits + c3_y off_y; // for _etch_bits + c3_c* err_c; +} u3_sifter; + +static void +etcher_init(u3_etcher* ech_u, c3_y* buf_y, c3_w cap_w) +{ + ech_u->buf_y = buf_y; + ech_u->len_w = 0; + ech_u->cap_w = cap_w; + ech_u->bit_d = 0; + ech_u->off_y = 0; +} + +static void +sifter_init(u3_sifter* sif_u, c3_y* buf_y, c3_w len_w) +{ + sif_u->buf_y = buf_y; + sif_u->rem_w = len_w; + sif_u->bit_d = 0; + sif_u->off_y = 0; + sif_u->err_c = NULL; +} + +static void +_sift_fail(u3_sifter* sif_u, c3_c* msg_c) +{ + if ( sif_u->err_c ) { + return; + } + sif_u->err_c = msg_c; + #ifdef MESA_ROUNDTRIP + u3l_log(RED_TEXT "sift fail: %s" DEF_TEXT, msg_c); + assert(!"sift fail"); + #endif +} + +static c3_y* +_etch_next(u3_etcher* ech_u, c3_w len_w) +{ + assert ( ech_u->off_y == 0 ); // ensure all bits were etched + assert ( ech_u->len_w + len_w <= ech_u->cap_w ); // ensure buffer is big enough + c3_y *res_y = ech_u->buf_y + ech_u->len_w; + ech_u->len_w += len_w; + return res_y; +} + +static c3_y* +_sift_next(u3_sifter* sif_u, c3_w len_w) +{ + assert ( sif_u->off_y == 0 ); // ensure all bits were sifted + if ( sif_u->err_c ) { + return NULL; + } + else if ( len_w > sif_u->rem_w ) { + _sift_fail(sif_u, "unexpected eof"); + } + c3_y *res_y = sif_u->buf_y; + sif_u->buf_y += len_w; + sif_u->rem_w -= len_w; + return res_y; +} + +static void +_etch_bytes(u3_etcher* ech_u, c3_y *buf_y, c3_w len_w) +{ + c3_y *res_y = _etch_next(ech_u, len_w); + memcpy(res_y, buf_y, len_w); +} + +static void +_sift_bytes(u3_sifter* sif_u, c3_y *buf_y, c3_w len_w) +{ + c3_y *res_y = _sift_next(sif_u, len_w); + if ( NULL == res_y ) { + memset(buf_y, 0, len_w); + return; + } + memcpy(buf_y, res_y, len_w); +} + +static c3_y* +_sift_bytes_alloc(u3_sifter* sif_u, c3_w len_w) +{ + c3_y *buf_y = c3_calloc(len_w); + _sift_bytes(sif_u, buf_y, len_w); + return buf_y; +} + +static void +_etch_byte(u3_etcher* ech_u, c3_y val_y) +{ + _etch_next(ech_u, 1)[0] = val_y; +} + +static c3_y +_sift_byte(u3_sifter* sif_u) +{ + c3_y *res_y = _sift_next(sif_u, 1); + return ( NULL == res_y ) ? 0 : res_y[0]; +} + +static void +_etch_short(u3_etcher* ech_u, c3_s val_s) +{ + c3_etch_short(_etch_next(ech_u, 2), val_s); +} + +static c3_y +_sift_short(u3_sifter* sif_u) +{ + c3_y *res_y = _sift_next(sif_u, 2); + return ( NULL == res_y ) ? 0 : c3_sift_short(res_y); +} + +static void +_etch_word(u3_etcher* ech_u, c3_w val_w) +{ + c3_etch_word(_etch_next(ech_u, 4), val_w); +} + +static c3_w +_sift_word(u3_sifter* sif_u) +{ + c3_y *res_y = _sift_next(sif_u, 4); + return ( NULL == res_y ) ? 0 : c3_sift_word(res_y); +} + +static void +_etch_chub(u3_etcher* ech_u, c3_d val_d) +{ + c3_etch_chub(_etch_next(ech_u, 8), val_d); +} + +static c3_d +_sift_chub(u3_sifter* sif_u) +{ + c3_y *res_y = _sift_next(sif_u, 8); + return ( NULL == res_y ) ? 0 : c3_sift_chub(res_y); +} + +static void +_etch_var_word(u3_etcher* ech_u, c3_w val_w, c3_w len_w) +{ + assert ( len_w <= 4 ); + c3_y *buf_y = _etch_next(ech_u, len_w); + for ( c3_w i = 0; i < len_w; i++ ) { + buf_y[i] = (val_w >> (8*i)) & 0xFF; + } +} + +static c3_w +_sift_var_word(u3_sifter* sif_u, c3_w len_w) +{ + assert ( len_w <= 4 ); + c3_y *res_y = _sift_next(sif_u, len_w); + if ( NULL == res_y ) { + return 0; + } + c3_w val_w = 0; + for ( c3_w i = 0; i < len_w; i++ ) { + val_w |= (res_y[i] << (8*i)); + } + return val_w; +} + +static void +_etch_var_chub(u3_etcher* ech_u, c3_d val_d, c3_w len_w) +{ + assert ( len_w <= 8 ); + c3_y *buf_y = _etch_next(ech_u, len_w); + for ( int i = 0; i < len_w; i++ ) { + buf_y[i] = (val_d >> (8*i)) & 0xFF; + } +} + +static c3_d +_sift_var_chub(u3_sifter* sif_u, c3_w len_w) +{ + assert ( len_w <= 8 ); + c3_y *res_y = _sift_next(sif_u, len_w); + if ( NULL == res_y ) { + return 0; + } + c3_d val_d = 0; + for ( int i = 0; i < len_w; i++ ) { + val_d |= (res_y[i] << (8*i)); + } + return val_d; +} + +static void +_etch_bits(u3_etcher* ech_u, c3_w wid_w, c3_d val_d) +{ + assert ( ech_u->off_y + wid_w <= 64 ); + ech_u->bit_d |= ((val_d&((1 << wid_w) - 1)) << ech_u->off_y); + ech_u->off_y += wid_w; + while ( ech_u->off_y >= 8 ) { + ech_u->buf_y[ech_u->len_w] = ech_u->bit_d & 0xFF; + ech_u->bit_d >>= 8; + ech_u->len_w += 1; + ech_u->off_y -= 8; + } +} + +static c3_d +_sift_bits(u3_sifter* sif_u, c3_w wid_w) +{ + assert ( wid_w <= 64 ); + while ( sif_u->off_y < wid_w ) { + c3_d byt_d = (sif_u->rem_w > 0) ? sif_u->buf_y[0] : 0; + sif_u->buf_y += 1; + sif_u->rem_w -= 1; + sif_u->bit_d |= (byt_d << sif_u->off_y); + sif_u->off_y += 8; + } + c3_d res_d = sif_u->bit_d & ((1 << wid_w) - 1); + sif_u->bit_d >>= wid_w; + sif_u->off_y -= wid_w; + return res_d; +} + +static void +_etch_ship(u3_etcher* ech_u, u3_ship who_u, c3_y len_y) +{ + assert ( len_y <= 16 ); + u3_ship_to_bytes(who_u, len_y, _etch_next(ech_u, len_y)); +} + +static void +_sift_ship(u3_sifter* sif_u, u3_ship who_u, c3_y len_y) +{ + assert ( len_y <= 16 ); + c3_y *res_y = _sift_next(sif_u, len_y); + if ( NULL == res_y ) { + who_u[0] = who_u[1] = 0; + return; + } + u3_ship_of_bytes(who_u, len_y, res_y); +} + +static void +_mesa_etch_head(u3_etcher* ech_u, u3_mesa_head* hed_u) +{ + if ( 1 != hed_u->pro_y ) { + u3l_log("etching bad head"); + } + _etch_bits(ech_u, 2, 0); // unused + _etch_bits(ech_u, 2, hed_u->nex_y); + _etch_bits(ech_u, 3, hed_u->pro_y); + _etch_bits(ech_u, 2, hed_u->typ_y); + _etch_bits(ech_u, 3, hed_u->hop_y); + _etch_bits(ech_u, 20, hed_u->mug_w); + _etch_word(ech_u, MESA_COOKIE); +} + +c3_o +mesa_is_new_pact(c3_y* buf_y, c3_w len_w) +{ + return __((len_w >= 8) && c3_sift_word(buf_y + 4) == MESA_COOKIE); +} + +void +mesa_sift_head(u3_sifter* sif_u, u3_mesa_head* hed_u) +{ + _sift_bits(sif_u, 2); // unused + hed_u->nex_y = _sift_bits(sif_u, 2); + hed_u->pro_y = _sift_bits(sif_u, 3); + hed_u->typ_y = _sift_bits(sif_u, 2); + hed_u->hop_y = _sift_bits(sif_u, 3); + hed_u->mug_w = _sift_bits(sif_u, 20); + if ( 1 != hed_u->pro_y ) { + _sift_fail(sif_u, "bad protocol"); + } + if ( _sift_word(sif_u) != MESA_COOKIE ) { + _sift_fail(sif_u, "bad cookie"); + } +} + +static void +_mesa_etch_name(u3_etcher *ech_u, u3_mesa_name* nam_u) +{ + u3_mesa_name_meta met_u = {0}; + met_u.ran_y = _mesa_rank(nam_u->her_u); + met_u.rif_y = safe_dec(_mesa_met3_w(nam_u->rif_w)); + + if ( c3y == nam_u->nit_o ) { + met_u.nit_y = 1; + met_u.tau_y = 0; + met_u.gaf_y = 0; + } + else { + met_u.nit_y = 0; + met_u.tau_y = (c3y == nam_u->aut_o) ? 1 : 0; + met_u.gaf_y = _mesa_make_chub_tag(nam_u->fra_d); + } + + _etch_bits(ech_u, 2, met_u.ran_y); + _etch_bits(ech_u, 2, met_u.rif_y); + _etch_bits(ech_u, 1, met_u.nit_y); + _etch_bits(ech_u, 1, met_u.tau_y); + _etch_bits(ech_u, 2, met_u.gaf_y); + c3_y her_y = 2 << met_u.ran_y; // XX confirm + _etch_ship(ech_u, nam_u->her_u, her_y); + _etch_var_word(ech_u, nam_u->rif_w, met_u.rif_y + 1); + _etch_byte(ech_u, nam_u->boq_y); + + if ( met_u.nit_y ) { + // init packet + } + else { + _etch_var_word(ech_u, nam_u->fra_d, 1 << met_u.gaf_y); + } + + _etch_short(ech_u, nam_u->pat_s); + _etch_bytes(ech_u, (c3_y*)nam_u->pat_c, nam_u->pat_s); +} + +static void +_mesa_sift_name(u3_sifter* sif_u, u3_mesa_name* nam_u) +{ + u3_mesa_name_meta met_u = {0}; + met_u.ran_y = _sift_bits(sif_u, 2); + met_u.rif_y = _sift_bits(sif_u, 2); + met_u.nit_y = _sift_bits(sif_u, 1); + met_u.tau_y = _sift_bits(sif_u, 1); + met_u.gaf_y = _sift_bits(sif_u, 2); + + nam_u->nit_o = __( met_u.nit_y == 1 ); + nam_u->aut_o = __( met_u.tau_y == 1 ); + + _sift_ship(sif_u, nam_u->her_u, 2 << met_u.ran_y); + nam_u->rif_w = _sift_var_word(sif_u, met_u.rif_y + 1); + nam_u->boq_y = _sift_byte(sif_u); + + if ( met_u.nit_y ) { + assert( !met_u.tau_y ); + assert( !met_u.gaf_y ); + // XX init packet + nam_u->fra_d = 0; + } + else { + nam_u->fra_d = _sift_var_word(sif_u, 1 << met_u.gaf_y); + } + + nam_u->pat_s = _sift_short(sif_u); + + nam_u->pat_c = c3_calloc(nam_u->pat_s + 1); + _sift_bytes(sif_u, (c3_y*)nam_u->pat_c, nam_u->pat_s); + nam_u->pat_c[nam_u->pat_s] = 0; +} + +static void +_mesa_etch_data(u3_etcher* ech_u, u3_mesa_data* dat_u) +{ + u3_mesa_data_meta met_u = {0}; + met_u.bot_y = _mesa_make_chub_tag(dat_u->tob_d); + met_u.aut_o = __(dat_u->aut_u.typ_e == AUTH_SIGN || dat_u->aut_u.typ_e == AUTH_HMAC); + met_u.auv_o = __(dat_u->aut_u.typ_e == AUTH_SIGN || dat_u->aut_u.typ_e == AUTH_NONE); + c3_y nel_y = _mesa_met3_w(dat_u->len_w); + met_u.men_y = c3_min(nel_y, 3); + _etch_bits(ech_u, 2, met_u.bot_y); + _etch_bits(ech_u, 1, met_u.aut_o); + _etch_bits(ech_u, 1, met_u.auv_o); + _etch_bits(ech_u, 2, 0); // unused + _etch_bits(ech_u, 2, met_u.men_y); + _etch_var_chub(ech_u, dat_u->tob_d, 1 << met_u.bot_y); + switch ( dat_u->aut_u.typ_e ) { + case AUTH_SIGN: { + _etch_bytes(ech_u, dat_u->aut_u.sig_y, 64); + } break; + case AUTH_HMAC: { + _etch_bytes(ech_u, dat_u->aut_u.mac_y, 16); + } break; + case AUTH_NONE: { + } break; + case AUTH_PAIR: { + _etch_bytes(ech_u, dat_u->aut_u.has_y[0], 32); + _etch_bytes(ech_u, dat_u->aut_u.has_y[1], 32); + } break; + } + + if ( 3 == met_u.men_y ) { + _etch_byte(ech_u, nel_y); + } + _etch_var_word(ech_u, dat_u->len_w, nel_y); + _etch_bytes(ech_u, dat_u->fra_y, dat_u->len_w); +} + +static void +_mesa_sift_data(u3_sifter* sif_u, u3_mesa_data* dat_u) +{ + u3_mesa_data_meta met_u = {0}; + met_u.bot_y = _sift_bits(sif_u, 2); + met_u.aut_o = _sift_bits(sif_u, 1); + met_u.auv_o = _sift_bits(sif_u, 1); + _sift_bits(sif_u, 2); // unused + met_u.men_y = _sift_bits(sif_u, 2); + + dat_u->tob_d = _sift_var_chub(sif_u, 1<aut_u.sig_y, 64); + dat_u->aut_u.typ_e = AUTH_SIGN; + } + else { + _sift_bytes(sif_u, dat_u->aut_u.mac_y, 16); + dat_u->aut_u.typ_e = AUTH_HMAC; + } + } + else { + if ( c3y == met_u.auv_o ) { + dat_u->aut_u.typ_e = AUTH_NONE; + } else { + _sift_bytes(sif_u, dat_u->aut_u.has_y[0], 32); + _sift_bytes(sif_u, dat_u->aut_u.has_y[1], 32); + dat_u->aut_u.typ_e = AUTH_PAIR; + } + } + + c3_y nel_y = met_u.men_y; + if ( 3 == met_u.men_y ) { + nel_y = _sift_byte(sif_u); + } + dat_u->len_w = _sift_var_word(sif_u, nel_y); + dat_u->fra_y = _sift_bytes_alloc(sif_u, dat_u->len_w); +} + +static void +_mesa_etch_hop_long(u3_etcher* ech_u, u3_mesa_hop_once* hop_u) +{ + _etch_byte(ech_u, hop_u->len_w); + _etch_bytes(ech_u, hop_u->dat_y, hop_u->len_w); +} + +static void +_mesa_sift_hop_long(u3_sifter* sif_u, u3_mesa_hop_once* hop_u) +{ + hop_u->len_w = _sift_byte(sif_u); + hop_u->dat_y = _sift_bytes_alloc(sif_u, hop_u->len_w); +} + +static void +_mesa_etch_page_pact(u3_etcher* ech_u, u3_mesa_page_pact* pag_u, u3_mesa_head* hed_u) +{ + _mesa_etch_name(ech_u, &pag_u->nam_u); + _mesa_etch_data(ech_u, &pag_u->dat_u); + + switch ( hed_u->nex_y ) { + case HOP_NONE: { + } break; + case HOP_SHORT: { + _etch_bytes(ech_u, pag_u->sot_u, 6); + } break; + case HOP_LONG: { + _mesa_etch_hop_long(ech_u, &pag_u->one_u); + } break; + case HOP_MANY: { + _etch_byte(ech_u, pag_u->man_u.len_w); + for ( c3_w i = 0; i < pag_u->man_u.len_w; i++ ) { + _mesa_etch_hop_long(ech_u, &pag_u->man_u.dat_y[i]); + } + } break; + default: { + return; + } break; + } +} + +static void +_mesa_sift_page_pact(u3_sifter* sif_u, u3_mesa_page_pact* pag_u, c3_y nex_y) +{ + _mesa_sift_name(sif_u, &pag_u->nam_u); + _mesa_sift_data(sif_u, &pag_u->dat_u); + + switch ( nex_y ) { + default: { + u3_assert(!"mesa: sift invalid hop type"); + } + case HOP_NONE: return; + case HOP_SHORT: { + _sift_bytes(sif_u, pag_u->sot_u, 6); + return; + } + case HOP_LONG: { + _mesa_sift_hop_long(sif_u, &pag_u->one_u); + return; + } + case HOP_MANY: { + pag_u->man_u.len_w = _sift_byte(sif_u); + pag_u->man_u.dat_y = c3_calloc(sizeof(u3_mesa_hop_once) * pag_u->man_u.len_w); + for ( c3_w i = 0; i < pag_u->man_u.len_w; i++ ) { + _mesa_sift_hop_long(sif_u, &pag_u->man_u.dat_y[i]); + } + return; + } + } +} + +static void +_mesa_etch_peek_pact(u3_etcher* ech_u, u3_mesa_peek_pact* pac_u) +{ + _mesa_etch_name(ech_u, &pac_u->nam_u); +} + +static void +_mesa_sift_peek_pact(u3_sifter* sif_u, u3_mesa_peek_pact* pac_u) +{ + _mesa_sift_name(sif_u, &pac_u->nam_u); +} + +static void +_mesa_etch_poke_pact(u3_etcher* ech_u, u3_mesa_poke_pact* pac_u) +{ + _mesa_etch_name(ech_u, &pac_u->nam_u); + _mesa_etch_name(ech_u, &pac_u->pay_u); + _mesa_etch_data(ech_u, &pac_u->dat_u); +} + +static void +_mesa_sift_poke_pact(u3_sifter* sif_u, u3_mesa_poke_pact* pac_u) +{ + _mesa_sift_name(sif_u, &pac_u->nam_u); + _mesa_sift_name(sif_u, &pac_u->pay_u); + _mesa_sift_data(sif_u, &pac_u->dat_u); +} + +static void +_mesa_etch_pact(u3_etcher* ech_u, u3_mesa_pact* pac_u) +{ + // use a separate etcher to make computing the mug easier + u3_etcher pec_u; + etcher_init(&pec_u, ech_u->buf_y + ech_u->len_w + 8, ech_u->cap_w - ech_u->len_w - 8); + + switch ( pac_u->hed_u.typ_y ) { + case PACT_POKE: { + _mesa_etch_poke_pact(&pec_u, &pac_u->pok_u); + } break; + case PACT_PAGE: { + _mesa_etch_page_pact(&pec_u, &pac_u->pag_u, &pac_u->hed_u); + } break; + case PACT_PEEK: { + _mesa_etch_peek_pact(&pec_u, &pac_u->pek_u); + } break; + default: { + u3l_log("bad pact type %u", pac_u->hed_u.typ_y); + } + } + // now we can compute the mug and write the header + pac_u->hed_u.mug_w = u3r_mug_bytes(pec_u.buf_y, pec_u.len_w) + & 0xFFFFF; + _mesa_etch_head(ech_u, &pac_u->hed_u); + + // the payload is already written into the correct spot, so we just need to + // adjust the length + ech_u->len_w += pec_u.len_w; +} + +static void +_mesa_sift_pact(u3_sifter* sif_u, u3_mesa_pact* pac_u) +{ + mesa_sift_head(sif_u, &pac_u->hed_u); + + // for mug, later + c3_y *mug_y = sif_u->buf_y; + c3_w pre_w = sif_u->rem_w; + + switch ( pac_u->hed_u.typ_y ) { + case PACT_PEEK: { + _mesa_sift_peek_pact(sif_u, &pac_u->pek_u); + } break; + case PACT_PAGE: { + _mesa_sift_page_pact(sif_u, &pac_u->pag_u, pac_u->hed_u.nex_y); + } break; + case PACT_POKE: { + _mesa_sift_poke_pact(sif_u, &pac_u->pok_u); + } break; + default: { + /* u3l_log("mesa: received unknown packet type"); */ + break; + } + } + + { + c3_w mug_w = u3r_mug_bytes(mug_y, pre_w - sif_u->rem_w) + & 0xFFFFF; + if ( mug_w != pac_u->hed_u.mug_w ) { + _sift_fail(sif_u, "bad mug"); + return; + } + } +} + +/* packet etch/sift, with roundtrip tests */ + +c3_w +mesa_etch_pact_to_buf(c3_y* buf_y, c3_w cap_w, u3_mesa_pact *pac_u) { + u3_etcher ech_u; + etcher_init(&ech_u, buf_y, cap_w); + _mesa_etch_pact(&ech_u, pac_u); + + #ifdef MESA_ROUNDTRIP + u3_mesa_pact poc_u; + u3_sifter sif_u; + sifter_init(&sif_u, ech_u.buf_y, ech_u.len_w); + _mesa_sift_pact(&sif_u, &poc_u); + if ( sif_u.rem_w && !sif_u.err_c ) { + u3l_log("mesa: etch roundtrip failed: %u trailing bytes", sif_u.rem_w); + _sift_fail(&sif_u, "trailing bytes"); + } + if ( sif_u.err_c ) { + u3l_log("mesa: roundtrip failed: %s", sif_u.err_c); + assert(!"roundtrip failed"); + } + _mesa_check_pacts_equal(&poc_u, pac_u); + mesa_free_pact(&poc_u); + #endif + + return ech_u.len_w; +} + +c3_c* +mesa_sift_pact_from_buf(u3_mesa_pact *pac_u, c3_y* buf_y, c3_w len_w) { + u3_sifter sif_u; + sifter_init(&sif_u, buf_y, len_w); + _mesa_sift_pact(&sif_u, pac_u); + if ( sif_u.rem_w && !sif_u.err_c ) { + _sift_fail(&sif_u, "trailing bytes"); + } + + #ifdef MESA_ROUNDTRIP + c3_y* bof_y = c3_calloc(len_w); + u3_etcher ech_u; + etcher_init(&ech_u, bof_y, len_w); + _mesa_etch_pact(&ech_u, pac_u); + u3_assert( 0 == memcmp(bof_y, buf_y, len_w) ); + c3_free(bof_y); + #endif + + return sif_u.err_c; +} + +/* sizing +*/ +static c3_w +_mesa_size_name(u3_mesa_name* nam_u) +{ + c3_w siz_w = 1; + u3_mesa_name_meta met_u; + + met_u.ran_y = _mesa_rank(nam_u->her_u); + met_u.rif_y = safe_dec(_mesa_met3_w(nam_u->rif_w)); + + siz_w += 2 << met_u.ran_y; + siz_w += met_u.rif_y + 1; + siz_w++; // bloq + + if ( nam_u->nit_o == c3n ) { + met_u.gaf_y = _mesa_make_chub_tag(nam_u->fra_d); + siz_w += _mesa_bytes_of_chub_tag(met_u.gaf_y); + } + + siz_w += 2; // path-length + siz_w += nam_u->pat_s; + + return siz_w; +} + +static c3_w +_mesa_size_data(u3_mesa_data* dat_u) +{ + c3_w siz_w = 1; + u3_mesa_data_meta met_u; + + met_u.bot_y = _mesa_make_chub_tag(dat_u->tob_d); + siz_w += _mesa_bytes_of_chub_tag(met_u.bot_y); + + switch ( dat_u->aut_u.typ_e ) { + case AUTH_SIGN: { + siz_w += 64; + } break; + + case AUTH_HMAC: { + siz_w += 16; + } break; + + case AUTH_NONE: { + } break; + + case AUTH_PAIR: { + siz_w += 64; + } break; + } + + c3_y nel_y = _mesa_met3_w(dat_u->len_w); + met_u.men_y = (3 >= nel_y) ? nel_y : 3; + + if ( 3 == met_u.men_y ) { + siz_w++; + } + + siz_w += nel_y; + siz_w += dat_u->len_w; + + return siz_w; +} + +static c3_w +_mesa_size_hops(u3_mesa_pact* pac_u) +{ + if ( PACT_PAGE != pac_u->hed_u.typ_y ) { + return 0; + } + + switch ( pac_u->hed_u.nex_y ) { + case HOP_NONE: return 0; + case HOP_SHORT: return 6; + case HOP_LONG: return 1 + pac_u->pag_u.one_u.len_w; + case HOP_MANY: { + c3_w siz_w = 0; + for ( c3_w i = 0; i < pac_u->pag_u.man_u.len_w; i++ ) { + siz_w += 1 + pac_u->pag_u.man_u.dat_y[i].len_w; + } + return siz_w; + } + default: u3_assert(!"mesa: invalid hop type"); + } +} + +c3_w +mesa_size_pact(u3_mesa_pact* pac_u) +{ + c3_w siz_w = 8; // header + cookie; + + switch ( pac_u->hed_u.typ_y ) { + case PACT_PEEK: { + siz_w += _mesa_size_name(&pac_u->pek_u.nam_u); + } break; + + case PACT_PAGE: { + siz_w += _mesa_size_name(&pac_u->pag_u.nam_u); + siz_w += _mesa_size_data(&pac_u->pag_u.dat_u); + siz_w += _mesa_size_hops(pac_u); + } break; + + case PACT_POKE: { + siz_w += _mesa_size_name(&pac_u->pok_u.nam_u); + siz_w += _mesa_size_name(&pac_u->pok_u.pay_u); + siz_w += _mesa_size_data(&pac_u->pok_u.dat_u); + } break; + + default: { + u3l_log("bad pact type %u", pac_u->hed_u.typ_y);//u3m_bail(c3__bail); + return 0; + } + } + + return siz_w; +} + +#ifdef PACT_TEST + +/* _mesa_encode_path(): produce buf_y as a parsed path +*/ +static u3_noun +_mesa_encode_path(c3_w len_w, c3_y* buf_y) +{ + u3_noun pro; + u3_noun* lit = &pro; + + { + u3_noun* hed; + u3_noun* tel; + c3_y* fub_y = buf_y; + c3_y car_y; + c3_w tem_w; + u3i_slab sab_u; + + while ( len_w-- ) { + car_y = *buf_y++; + if ( len_w == 0 ) { + buf_y++; + car_y = 47; + } + + if ( 47 == car_y ) { + tem_w = buf_y - fub_y - 1; + u3i_slab_bare(&sab_u, 3, tem_w); + sab_u.buf_w[sab_u.len_w - 1] = 0; + memcpy(sab_u.buf_y, fub_y, tem_w); + + *lit = u3i_defcons(&hed, &tel); + *hed = u3i_slab_moot(&sab_u); + lit = tel; + fub_y = buf_y; + } + } + } + + *lit = u3_nul; + + return pro; +} + +#define cmp_scalar(nam, str, fmt) \ + if ( hav_u->nam != ned_u->nam ) { \ + fprintf(stderr, "mesa test cmp " str " differ:\r\n" \ + " have: " fmt "\r\n" \ + " need: " fmt "\r\n", \ + hav_u->nam, ned_u->nam); \ + ret_i = 1; \ + } + +#define cmp_string(nam, siz, str) \ + if ( memcmp(hav_u->nam, ned_u->nam, siz) ) { \ + fprintf(stderr, "mesa test cmp " str " differ:\r\n" \ + " have: %*.s\r\n" \ + " need: %*.s\r\n", \ + siz, hav_u->nam, siz, ned_u->nam); \ + ret_i = 1; \ + } + +#define cmp_buffer(nam, siz, str) \ + if ( memcmp(hav_u->nam, ned_u->nam, siz) ) { \ + fprintf(stderr, "mesa test cmp " str "\r\n"); \ + ret_i = 1; \ + } + +static c3_i +_test_cmp_head(u3_mesa_head* hav_u, u3_mesa_head* ned_u) +{ + c3_i ret_i = 0; + + cmp_scalar(nex_y, "head: next", "%u"); + cmp_scalar(pro_y, "head: protocol", "%u"); + cmp_scalar(typ_y, "head: type", "%u"); + cmp_scalar(hop_y, "head: hop", "%u"); + cmp_scalar(mug_w, "head: mug", "%u"); + + return ret_i; +} + +static c3_i +_test_cmp_name(u3_mesa_name* hav_u, u3_mesa_name* ned_u) +{ + c3_i ret_i = 0; + + cmp_buffer(her_d, sizeof(ned_u->her_u), "name: ships differ"); + + cmp_scalar(rif_w, "name: rifts", "%u"); + cmp_scalar(boq_y, "name: bloqs", "%u"); + cmp_scalar(nit_o, "name: inits", "%u"); + cmp_scalar(aut_o, "name: auths", "%u"); + cmp_scalar(fra_w, "name: fragments", "%u"); + cmp_scalar(pat_s, "name: path-lengths", "%u"); + + cmp_string(pat_c, ned_u->pat_s, "name: paths"); + + return ret_i; +} + +static c3_i +_test_cmp_data(u3_mesa_data* hav_u, u3_mesa_data* ned_u) +{ + c3_i ret_i = 0; + + cmp_scalar(tot_w, "data: total packets", "%u"); + + cmp_scalar(aut_u.typ_e, "data: auth-types", "%u"); + cmp_buffer(aut_u.sig_y, 64, "data: sig|hmac|null"); + + cmp_scalar(aut_u.len_y, "data: hash-lengths", "%u"); + cmp_buffer(aut_u.has_y, ned_u->aut_u.len_y, "data: hashes"); + + cmp_scalar(len_w, "data: fragments-lengths", "%u"); + cmp_buffer(fra_y, ned_u->len_w, "data: fragments"); + + return ret_i; +} + +static c3_i +_test_pact(u3_mesa_pact* pac_u) +{ + c3_y* buf_y = c3_calloc(PACT_SIZE); + c3_w len_w = mesa_etch_pact(buf_y, pac_u); + c3_i ret_i = 0; + c3_i bot_i = 0; + c3_w sif_w; + + u3_mesa_pact nex_u; + memset(&nex_u, 0, sizeof(u3_mesa_pact)); + + if ( !len_w ) { + fprintf(stderr, "pact: etch failed\r\n"); + ret_i = 1; goto done; + } + else if ( len_w > PACT_SIZE ) { + fprintf(stderr, "pact: etch overflowed: %u\r\n", len_w); + ret_i = 1; goto done; + } + + if ( len_w != (sif_w = _mesa_sift_pact(&nex_u, buf_y, len_w)) ) { + fprintf(stderr, "pact: sift failed len=%u sif=%u\r\n", len_w, sif_w); + _log_buf(buf_y, len_w); + ret_i = 1; goto done; + } + + bot_i = 1; + + if ( _test_cmp_head(&nex_u.hed_u, &pac_u->hed_u) ) { + fprintf(stderr, "pact: head cmp fail\r\n"); + ret_i = 1; + } + + switch ( pac_u->hed_u.typ_y ) { + case PACT_PEEK: { + if ( _test_cmp_name(&nex_u.pek_u.nam_u, &pac_u->pek_u.nam_u) ) { + fprintf(stderr, "%%peek name cmp fail\r\n"); + ret_i = 1; + } + } break; + + case PACT_PAGE: { + if ( _test_cmp_name(&nex_u.pag_u.nam_u, &pac_u->pag_u.nam_u) ) { + fprintf(stderr, "%%page name cmp fail\r\n"); + ret_i = 1; + } + else if ( _test_cmp_data(&nex_u.pag_u.dat_u, &pac_u->pag_u.dat_u) ) { + fprintf(stderr, "%%page data cmp fail\r\n"); + ret_i = 1; + } + } break; + + case PACT_POKE: { + if ( _test_cmp_name(&nex_u.pok_u.nam_u, &pac_u->pok_u.nam_u) ) { + fprintf(stderr, "%%poke name cmp fail\r\n"); + ret_i = 1; + } + else if ( _test_cmp_name(&nex_u.pok_u.pay_u, &pac_u->pok_u.pay_u) ) { + fprintf(stderr, "%%poke pay-name cmp fail\r\n"); + ret_i = 1; + } + else if ( _test_cmp_data(&nex_u.pok_u.dat_u, &pac_u->pok_u.dat_u) ) { + fprintf(stderr, "%%poke data cmp fail\r\n"); + ret_i = 1; + } + } break; + + default: { + fprintf(stderr, "test: strange packet\r\n"); + ret_i = 1; + } + } + +done: + if ( ret_i ) { + _log_head(&pac_u->hed_u); + log_pact(pac_u); + _log_buf(buf_y, len_w); + + if ( bot_i ) { + u3l_log(RED_TEXT); + _log_head(&nex_u.hed_u); + log_pact(&nex_u); + u3l_log(DEF_TEXT); + } + } + + c3_free(buf_y); + + return ret_i; +} + +static c3_y +_test_rand_bit(void* ptr_v) +{ + return rand() & 1; +} + +static c3_y +_test_rand_bits(void* ptr_v, c3_y len_y) +{ + assert( 8 >= len_y ); + return rand() & ((1 << len_y) - 1); +} + +static c3_w +_test_rand_word(void* ptr_v) +{ + c3_w low_w = rand(); + c3_w hig_w = rand(); + return (hig_w << 16) ^ (low_w & ((1 << 16) - 1)); +} + +static c3_y +_test_rand_gulf_y(void* ptr_v, c3_y top_y) +{ + c3_y bit_y = c3_bits_word(top_y); + c3_y res_y = 0; + + if ( !bit_y ) return res_y; + + while ( 1 ) { + res_y = _test_rand_bits(ptr_v, bit_y); + + if ( res_y < top_y ) { + return res_y; + } + } +} + +static c3_w +_test_rand_gulf_w(void* ptr_v, c3_w top_w) +{ + c3_w bit_w = c3_bits_word(top_w); + c3_w res_w = 0; + + if ( !bit_w ) return res_w; + + while ( 1 ) { + res_w = _test_rand_word(ptr_v); + res_w &= (1 << bit_w) - 1; + + if ( res_w < top_w ) { + return res_w; + } + } +} + +static void +_test_rand_bytes(void* ptr_v, c3_w len_w, c3_y* buf_y) +{ + c3_w max_w = len_w / 2; + + while ( max_w-- ) { + c3_w wor_w = rand(); + *buf_y++ = (wor_w >> 0) & 0xff; + *buf_y++ = (wor_w >> 8) & 0xff; + } + + if ( len_w & 1 ) { + *buf_y = rand() & 0xff; + } +} + +const char* ta_c = "-~_.0123456789abcdefghijklmnopqrstuvwxyz"; + +static void +_test_rand_knot(void* ptr_v, c3_w len_w, c3_c* not_c) +{ + for ( c3_w i_w = 0; i_w < len_w; i_w++ ) { + *not_c++ = ta_c[_test_rand_gulf_y(ptr_v, 40)]; + } +} + +static void +_test_rand_path(void* ptr_v, c3_s len_s, c3_c* pat_c) +{ + c3_s not_s = 0; + + while ( len_s ) { + not_s = _test_rand_gulf_w(ptr_v, len_s); + _test_rand_knot(ptr_v, not_s, pat_c); + pat_c[not_s] = '/'; + pat_c += not_s + 1; + len_s -= not_s + 1; + } +} + +static void +_test_make_head(void* ptr_v, u3_mesa_head* hed_u) +{ + hed_u->nex_y = NEXH_NONE; // XX + hed_u->pro_y = 1; + hed_u->typ_y = _test_rand_gulf_y(ptr_v, 3) + 1; + hed_u->hop_y = _test_rand_gulf_y(ptr_v, 8); + hed_u->mug_w = 0; + // XX set mug_w in etch? +} + +static void +_test_make_name(void* ptr_v, c3_s pat_s, u3_mesa_name* nam_u) +{ + _test_rand_bytes(ptr_v, 16, (c3_y*)nam_u->her_u); + nam_u->rif_w = _test_rand_word(ptr_v); + + nam_u->pat_s = _test_rand_gulf_w(ptr_v, pat_s); + nam_u->pat_c = c3_malloc(nam_u->pat_s + 1); + _test_rand_path(ptr_v, nam_u->pat_s, nam_u->pat_c); + nam_u->pat_c[nam_u->pat_s] = 0; + + nam_u->boq_y = _test_rand_bits(ptr_v, 8); + nam_u->nit_o = _test_rand_bits(ptr_v, 1); + + if ( c3y == nam_u->nit_o ) { + nam_u->aut_o = c3n; + nam_u->fra_w = 0; + } + else { + nam_u->aut_o = _test_rand_bits(ptr_v, 1); + nam_u->fra_w = _test_rand_word(ptr_v); + } +} + +static void +_test_make_data(void* ptr_v, u3_mesa_data* dat_u) +{ + dat_u->tot_w = _test_rand_word(ptr_v); + + memset(dat_u->aut_u.sig_y, 0, 64); + dat_u->aut_u.len_y = 0; + memset(dat_u->aut_u.has_y, 0, sizeof(dat_u->aut_u.has_y)); + + switch ( dat_u->aut_u.typ_e = _test_rand_bits(ptr_v, 2) ) { + case AUTH_NEXT: { + dat_u->aut_u.len_y = 2; + } break; + + case AUTH_SIGN: { + dat_u->aut_u.len_y = _test_rand_gulf_y(ptr_v, 3); + _test_rand_bytes(ptr_v, 64, dat_u->aut_u.sig_y); + } break; + + case AUTH_HMAC: { + dat_u->aut_u.len_y = _test_rand_gulf_y(ptr_v, 3); + _test_rand_bytes(ptr_v, 16, dat_u->aut_u.mac_y); + } break; + + default: break; + } + + for ( c3_w i_w = 0; i_w < dat_u->aut_u.len_y; i_w++ ) { + _test_rand_bytes(ptr_v, 32, dat_u->aut_u.has_y[i_w]); + } + + dat_u->len_w = _test_rand_gulf_w(ptr_v, 1024); + dat_u->fra_y = c3_calloc(dat_u->len_w); + _test_rand_bytes(ptr_v, dat_u->len_w, dat_u->fra_y); +} + +static void +_test_make_pact(void* ptr_v, u3_mesa_pact* pac_u) +{ + _test_make_head(ptr_v, &pac_u->hed_u); + + switch ( pac_u->hed_u.typ_y ) { + case PACT_PEEK: { + _test_make_name(ptr_v, 277, &pac_u->pek_u.nam_u); + } break; + + case PACT_PAGE: { + _test_make_name(ptr_v, 277, &pac_u->pag_u.nam_u); + _test_make_data(ptr_v, &pac_u->pag_u.dat_u); + } break; + + case PACT_POKE: { + _test_make_name(ptr_v, 124, &pac_u->pok_u.nam_u); + _test_make_name(ptr_v, 124, &pac_u->pok_u.pay_u); + _test_make_data(ptr_v, &pac_u->pok_u.dat_u); + } break; + + default: break; // XX + } +} + +static c3_i +_test_rand_pact(c3_w bat_w) +{ + u3_mesa_pact pac_u; + void* ptr_v = 0; + + fprintf(stderr, "pact: test roundtrip %u random packets\r\n", bat_w); + + for ( c3_w i_w = 0; i_w < bat_w; i_w++ ) { + _test_make_pact(ptr_v, &pac_u); + + if ( _test_pact(&pac_u) ) { + fprintf(stderr, RED_TEXT "pact: roundtrip attempt %u failed\r\n", i_w); + exit(1); + } + + // XX free pat_s / buf_y + } + + return 0; +} + +static void +_test_sift_page() +{ + u3_mesa_pact pac_u; + memset(&pac_u,0, sizeof(u3_mesa_pact)); + pac_u.hed_u.typ_y = PACT_PAGE; + pac_u.hed_u.pro_y = 1; + u3l_log("%%page checking sift/etch idempotent"); + u3_mesa_name* nam_u = &pac_u.pag_u.nam_u; + + { + u3_noun her = u3v_wish("~hastuc-dibtux"); + u3r_chubs(0, 2, nam_u->her_u, her); + u3z(her); + } + nam_u->rif_w = 15; + nam_u->pat_c = "foo/bar"; + nam_u->pat_s = strlen(nam_u->pat_c); + nam_u->boq_y = 13; + nam_u->fra_w = 54; + nam_u->nit_o = c3n; + + u3_mesa_data* dat_u = &pac_u.pag_u.dat_u; + dat_u->aut_u.typ_e = AUTH_NONE; + dat_u->tot_w = 1000; + dat_u->len_w = 1024; + dat_u->fra_y = c3_calloc(1024); + // dat_u->fra_y[1023] = 1; + + if ( _test_pact(&pac_u) ) { + fprintf(stderr, RED_TEXT "%%page failed\r\n"); + exit(1); + } +} + + +static void +_test_encode_path(c3_c* pat_c) +{ + u3_noun wan = u3do("stab", u3dt("cat", 3, '/', u3i_string(pat_c))); + u3_noun hav = _mesa_encode_path(strlen(pat_c), (c3_y*)pat_c); + + if ( c3n == u3r_sing(wan, hav) ) { + u3l_log(RED_TEXT); + u3l_log("path encoding mismatch"); + u3m_p("want", wan); + u3m_p("have", hav); + exit(1); + } +} + + +static void +_setup() +{ + c3_d len_d = u3_Ivory_pill_len; + c3_y* byt_y = u3_Ivory_pill; + u3_cue_xeno* sil_u; + u3_weak pil; + + u3C.wag_w |= u3o_hashless; + u3m_boot_lite(1 << 26); + sil_u = u3s_cue_xeno_init_with(ur_fib27, ur_fib28); + if ( u3_none == (pil = u3s_cue_xeno_with(sil_u, len_d, byt_y)) ) { + printf("*** fail _setup 1\n"); + exit(1); + } + u3s_cue_xeno_done(sil_u); + if ( c3n == u3v_boot_lite(pil) ) { + printf("*** fail _setup 2\n"); + exit(1); + } + + { + c3_w pid_w = getpid(); + srand(pid_w); + fprintf(stderr, "test: seeding rand() with pid %u\r\n", pid_w); + } +} + +int main() +{ + _setup(); + + _test_rand_pact(100000); + + _test_encode_path("foo/bar/baz"); + _test_encode_path("publ/0/xx//1/foo/g"); + return 0; +} + + +#endif diff --git a/pkg/vere/io/serial.h b/pkg/vere/io/serial.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pkg/vere/io/term.c b/pkg/vere/io/term.c index 2e6e20895c..014f2cc90c 100644 --- a/pkg/vere/io/term.c +++ b/pkg/vere/io/term.c @@ -1603,6 +1603,13 @@ _term_io_talk(u3_auto* car_u) u3_noun wir = u3nt(c3__term, '1', u3_nul); u3_noun cad; + // send born event + // + { + cad = u3nc(c3__born, u3_nul); + _term_ovum_plan(car_u, u3k(wir), cad); + } + // send terminal dimensions // { @@ -1639,6 +1646,17 @@ _reck_orchid(u3_noun fot, u3_noun txt, c3_l* tid_l) } } +/* _term_io_quiz(): handle quiz (query to serf). +*/ +static void +_term_io_quiz(void* vod_p, u3_noun res) +{ + u3_auto* car_u = (u3_auto*)vod_p; + u3_noun wir = u3nt(c3__term, '1', u3_nul); + u3_noun cad = u3k(res); + u3_auto_plan(car_u, u3_ovum_init(0, c3__d, wir, cad)); +} + /* _term_io_kick(): apply effects. */ static c3_o @@ -1727,6 +1745,17 @@ _term_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) ret_o = c3y; u3_pier_pack(car_u->pir_u); } break; + + case c3__quac: { + ret_o = c3y; + u3_writ* wit_u = u3_lord_writ_new(u3K.pir_u->god_u); + wit_u->typ_e = u3_writ_quiz; + wit_u->qui_u.ptr_v = car_u; + wit_u->qui_u.quiz_f = _term_io_quiz; + + u3_lord_writ_plan(u3K.pir_u->god_u, wit_u); + + } break; } } } diff --git a/pkg/vere/king.c b/pkg/vere/king.c index 8d5402cb30..4f2009bb09 100644 --- a/pkg/vere/king.c +++ b/pkg/vere/king.c @@ -271,11 +271,11 @@ _king_pier(u3_noun pier) u3z(pier); } -/* _king_curl_alloc(): allocate a response buffer for curl +/* king_curl_alloc(): allocate a response buffer for curl ** XX deduplicate with dawn.c */ -static size_t -_king_curl_alloc(void* dat_v, size_t uni_t, size_t mem_t, void* buf_v) +size_t +king_curl_alloc(void* dat_v, size_t uni_t, size_t mem_t, void* buf_v) { uv_buf_t* buf_u = buf_v; @@ -289,11 +289,11 @@ _king_curl_alloc(void* dat_v, size_t uni_t, size_t mem_t, void* buf_v) return siz_t; } -/* _king_curl_bytes(): HTTP GET url_c, produce response body bytes. +/* king_curl_bytes(): HTTP GET url_c, produce response body bytes. ** XX deduplicate with dawn.c */ -static c3_i -_king_curl_bytes(c3_c* url_c, c3_w* len_w, c3_y** hun_y, c3_t veb_t) +c3_i +king_curl_bytes(c3_c* url_c, c3_w* len_w, c3_y** hun_y, c3_t veb_t) { c3_i ret_i = 0; CURL *cul_u; @@ -309,8 +309,9 @@ _king_curl_bytes(c3_c* url_c, c3_w* len_w, c3_y** hun_y, c3_t veb_t) u3K.ssl_curl_f(cul_u); curl_easy_setopt(cul_u, CURLOPT_URL, url_c); - curl_easy_setopt(cul_u, CURLOPT_WRITEFUNCTION, _king_curl_alloc); + curl_easy_setopt(cul_u, CURLOPT_WRITEFUNCTION, king_curl_alloc); curl_easy_setopt(cul_u, CURLOPT_WRITEDATA, (void*)&buf_u); + curl_easy_setopt(cul_u, CURLOPT_SERVER_RESPONSE_TIMEOUT, 30); while ( 5 > try_y ) { sleep(try_y++); @@ -329,6 +330,9 @@ _king_curl_bytes(c3_c* url_c, c3_w* len_w, c3_y** hun_y, c3_t veb_t) u3l_log("curl: error fetching %s: HTTP %ld", url_c, cod_i); } ret_i = -2; + if ( 400 <= cod_i && cod_i < 500 ) { + break; + } } else { *len_w = buf_u.len; @@ -352,7 +356,7 @@ _king_get_atom(c3_c* url_c) c3_y* hun_y; u3_noun pro; - if ( _king_curl_bytes(url_c, &len_w, &hun_y, 1) ) { + if ( king_curl_bytes(url_c, &len_w, &hun_y, 1) ) { u3_king_bail(); exit(1); } @@ -432,7 +436,7 @@ u3_king_next(c3_c* pac_c, c3_c** out_c) // skip printfs on failed requests (/next is usually not present) //REVIEW new retry logic means this case will take longer. make retries optional? // - if ( _king_curl_bytes(url_c, &len_w, &hun_y, 0) ) { + if ( king_curl_bytes(url_c, &len_w, &hun_y, 0) ) { c3_free(url_c); ret_i = asprintf(&url_c, "%s/%s/last", ver_hos_c, pac_c); @@ -441,7 +445,7 @@ u3_king_next(c3_c* pac_c, c3_c** out_c) // enable printfs on failed requests (/last must be present) // XX support channel redirections // - if ( _king_curl_bytes(url_c, &len_w, &hun_y, 1) ) + if ( king_curl_bytes(url_c, &len_w, &hun_y, 1) ) { c3_free(url_c); return -2; @@ -1654,7 +1658,6 @@ u3_king_bail(void) void u3_king_grab(void* vod_p) { - c3_w tot_w = 0; FILE* fil_u; u3_assert( u3R == &(u3H->rod_u) ); @@ -1690,11 +1693,32 @@ u3_king_grab(void* vod_p) } #endif - tot_w += u3m_mark(fil_u); - tot_w += u3_pier_mark(fil_u); + u3m_quac** all_u = c3_malloc(sizeof(*all_u)*6); + + u3m_quac** var_u = u3m_mark(); + all_u[0] = var_u[0]; + all_u[1] = var_u[1]; + all_u[2] = var_u[2]; + all_u[3] = var_u[3]; + c3_free(var_u); + + c3_w tot_w = all_u[0]->siz_w + all_u[1]->siz_w + + all_u[2]->siz_w + all_u[3]->siz_w; + + all_u[4] = c3_calloc(sizeof(*all_u[4])); + all_u[4]->nam_c = "total marked"; + all_u[4]->siz_w = tot_w; + + all_u[5] = c3_calloc(sizeof(*all_u[5])); + all_u[5]->nam_c = "sweep"; + all_u[5]->siz_w = u3a_sweep(); + + for ( c3_w i_w = 0; i_w < 6; i_w++ ) { + u3a_print_quac(fil_u, 0, all_u[i_w]); + u3a_quac_free(all_u[i_w]); + } - u3a_print_memory(fil_u, "total marked", tot_w); - u3a_print_memory(fil_u, "sweep", u3a_sweep()); + c3_free(all_u); #ifdef U3_MEMORY_LOG { diff --git a/pkg/vere/lord.c b/pkg/vere/lord.c index b7c03dfe6f..d7ebf20e8f 100644 --- a/pkg/vere/lord.c +++ b/pkg/vere/lord.c @@ -23,6 +23,7 @@ [%peek mil=@ sam=*] :: gang (each path $%([%once @tas @tas path] [%beam @tas beam])) [%play eve=@ lit=(list ?((pair @da ovum) *))] [%work mil=@ job=(pair @da ovum)] + [%quiz $%([%quac ~])] == :: +plea: from serf to king :: @@ -31,6 +32,7 @@ [%ripe [pro=%1 hon=@ nok=@] eve=@ mug=@] [%slog pri=@ tank] [%flog cord] + [%quiz $%([%quac p=*])] $: %peek $% [%done dat=(unit (cask))] [%bail dud=goof] @@ -532,6 +534,16 @@ _lord_plea_play(u3_lord* god_u, u3_noun dat) u3z(dat); } +/* _lord_plea_quiz(): handle quiz (query to serf). + */ +static void +_lord_plea_quiz(u3_lord* god_u, u3_noun dat) +{ + u3_writ* wit_u = _lord_writ_need(god_u, u3_writ_quiz); + wit_u->qui_u.quiz_f(wit_u->qui_u.ptr_v, dat); + u3z(dat); +} + /* _lord_work_spin(): update spinner if more work is in progress. */ static void @@ -760,15 +772,19 @@ _lord_on_plea(void* ptr_v, c3_d len_d, c3_y* byt_y) case c3__ripe: { _lord_plea_ripe(god_u, u3k(dat)); } break; + + case c3__quiz: { + _lord_plea_quiz(god_u, u3k(dat)); + } break; } u3z(jar); } -/* _lord_writ_new(): allocate a new writ. +/* u3_lord_writ_new(): allocate a new writ. */ -static u3_writ* -_lord_writ_new(u3_lord* god_u) +u3_writ* +u3_lord_writ_new(u3_lord* god_u) { u3_writ* wit_u = c3_calloc(sizeof(*wit_u)); return wit_u; @@ -830,6 +846,10 @@ _lord_writ_make(u3_lord* god_u, u3_writ* wit_u) // msg = u3nt(c3__live, c3__exit, 0); } break; + + case u3_writ_quiz: { + msg = u3nt(c3__quiz, c3__quac, u3_nul); + } break; } return msg; @@ -867,10 +887,10 @@ _lord_writ_send(u3_lord* god_u, u3_writ* wit_u) } } -/* _lord_writ_plan(): enqueue a writ and send. +/* u3_lord_writ_plan(): enqueue a writ and send. */ -static void -_lord_writ_plan(u3_lord* god_u, u3_writ* wit_u) +void +u3_lord_writ_plan(u3_lord* god_u, u3_writ* wit_u) { if ( !god_u->ent_u ) { u3_assert( !god_u->ext_u ); @@ -892,7 +912,7 @@ _lord_writ_plan(u3_lord* god_u, u3_writ* wit_u) void u3_lord_peek(u3_lord* god_u, u3_pico* pic_u) { - u3_writ* wit_u = _lord_writ_new(god_u); + u3_writ* wit_u = u3_lord_writ_new(god_u); wit_u->typ_e = u3_writ_peek; wit_u->pek_u = c3_calloc(sizeof(*wit_u->pek_u)); wit_u->pek_u->ptr_v = pic_u->ptr_v; @@ -923,7 +943,7 @@ u3_lord_peek(u3_lord* god_u, u3_pico* pic_u) // XX cache check, unless last // - _lord_writ_plan(god_u, wit_u); + u3_lord_writ_plan(god_u, wit_u); } /* u3_lord_play(): recompute batch. @@ -931,7 +951,7 @@ u3_lord_peek(u3_lord* god_u, u3_pico* pic_u) void u3_lord_play(u3_lord* god_u, u3_info fon_u) { - u3_writ* wit_u = _lord_writ_new(god_u); + u3_writ* wit_u = u3_lord_writ_new(god_u); wit_u->typ_e = u3_writ_play; wit_u->fon_u = fon_u; @@ -939,7 +959,7 @@ u3_lord_play(u3_lord* god_u, u3_info fon_u) // // u3_assert( !pay_u.ent_u->nex_u ); - _lord_writ_plan(god_u, wit_u); + u3_lord_writ_plan(god_u, wit_u); } /* u3_lord_work(): attempt work. @@ -947,7 +967,7 @@ u3_lord_play(u3_lord* god_u, u3_info fon_u) void u3_lord_work(u3_lord* god_u, u3_ovum* egg_u, u3_noun job) { - u3_writ* wit_u = _lord_writ_new(god_u); + u3_writ* wit_u = u3_lord_writ_new(god_u); wit_u->typ_e = u3_writ_work; wit_u->wok_u.egg_u = egg_u; wit_u->wok_u.job = job; @@ -961,7 +981,7 @@ u3_lord_work(u3_lord* god_u, u3_ovum* egg_u, u3_noun job) god_u->pin_o = c3y; } - _lord_writ_plan(god_u, wit_u); + u3_lord_writ_plan(god_u, wit_u); } /* u3_lord_save(): save a snapshot. @@ -973,9 +993,9 @@ u3_lord_save(u3_lord* god_u) return c3n; } else { - u3_writ* wit_u = _lord_writ_new(god_u); + u3_writ* wit_u = u3_lord_writ_new(god_u); wit_u->typ_e = u3_writ_save; - _lord_writ_plan(god_u, wit_u); + u3_lord_writ_plan(god_u, wit_u); return c3y; } } @@ -989,9 +1009,9 @@ u3_lord_cram(u3_lord* god_u) return c3n; } else { - u3_writ* wit_u = _lord_writ_new(god_u); + u3_writ* wit_u = u3_lord_writ_new(god_u); wit_u->typ_e = u3_writ_cram; - _lord_writ_plan(god_u, wit_u); + u3_lord_writ_plan(god_u, wit_u); return c3y; } } @@ -1001,9 +1021,9 @@ u3_lord_cram(u3_lord* god_u) void u3_lord_meld(u3_lord* god_u) { - u3_writ* wit_u = _lord_writ_new(god_u); + u3_writ* wit_u = u3_lord_writ_new(god_u); wit_u->typ_e = u3_writ_meld; - _lord_writ_plan(god_u, wit_u); + u3_lord_writ_plan(god_u, wit_u); } /* u3_lord_pack(): defragment persistent state. @@ -1011,9 +1031,9 @@ u3_lord_meld(u3_lord* god_u) void u3_lord_pack(u3_lord* god_u) { - u3_writ* wit_u = _lord_writ_new(god_u); + u3_writ* wit_u = u3_lord_writ_new(god_u); wit_u->typ_e = u3_writ_pack; - _lord_writ_plan(god_u, wit_u); + u3_lord_writ_plan(god_u, wit_u); } /* u3_lord_exit(): shutdown gracefully. @@ -1021,9 +1041,9 @@ u3_lord_pack(u3_lord* god_u) void u3_lord_exit(u3_lord* god_u) { - u3_writ* wit_u = _lord_writ_new(god_u); + u3_writ* wit_u = u3_lord_writ_new(god_u); wit_u->typ_e = u3_writ_exit; - _lord_writ_plan(god_u, wit_u); + u3_lord_writ_plan(god_u, wit_u); // XX set timer, then halt } diff --git a/pkg/vere/main.c b/pkg/vere/main.c index 1b09ccce3f..cc6c83e7fd 100644 --- a/pkg/vere/main.c +++ b/pkg/vere/main.c @@ -194,6 +194,7 @@ _main_init(void) u3_Host.ops_u.sap_w = 120; /* aka 2 minutes */ u3_Host.ops_u.lut_y = 31; /* aka 2G */ u3_Host.ops_u.lom_y = 31; + u3_Host.ops_u.jum_y = 23; /* aka 1MB */ u3_Host.ops_u.siz_i = #if (defined(U3_CPU_aarch64) && defined(U3_OS_linux)) @@ -269,6 +270,7 @@ _main_getopt(c3_i argc, c3_c** argv) { "import", required_argument, NULL, 'i' }, { "ivory-pill", required_argument, NULL, 'J' }, { "json-trace", no_argument, NULL, 'j' }, + { "jumbo-bloq", required_argument, NULL, c3__bloq }, { "kernel-stage", required_argument, NULL, 'K' }, { "key-file", required_argument, NULL, 'k' }, { "loom", required_argument, NULL, c3__loom }, @@ -365,6 +367,15 @@ _main_getopt(c3_i argc, c3_c** argv) } // special args // + case c3__bloq: { + if (_main_readw(optarg, 30, &arg_w)) { + return c3n; + } else u3_Host.ops_u.jum_y = arg_w; + if ( 13 > u3_Host.ops_u.jum_y ) { + return c3n; + } + break; + } case c3__loom: { if (_main_readw_loom("loom", &u3_Host.ops_u.lom_y)) { return c3n; @@ -844,10 +855,11 @@ u3_ve_usage(c3_i argc, c3_c** argv) "-i, --import FILE Import pier state from jamfile\n", "-J, --ivory-pill PILL Use custom ivory pill\n", "-j, --json-trace Create json trace file in .urb/put/trace\n", + " --jumbo-bloq BLOQ Set Ames jumbo frame bloq size\n", "-K, --kernel-stage STAGE Start at Hoon kernel version stage\n", "-k, --key-file KEYS Private key file (see also -G)\n", "-L, --local Local networking only\n", - " --loom Set loom to binary exponent (31 == 2GB)\n" + " --loom EXPO Set loom to binary exponent (31 == 2GB)\n" "-l, --lite-boot Most-minimal startup\n", "-M, --keep-cache-limit LIMIT Set persistent memo cache max size; 0 means default\n", "-n, --replay-to NUMBER Replay up to event\n", @@ -1769,7 +1781,7 @@ _cw_grab(c3_i argc, c3_c* argv[]) u3m_boot(u3_Host.dir_c, (size_t)1 << u3_Host.ops_u.lom_y); u3C.wag_w |= u3o_hashless; - u3_serf_grab(); + u3z(u3_serf_grab(c3y)); u3m_stop(); } diff --git a/pkg/vere/pier.c b/pkg/vere/pier.c index 1e8c25b110..9be46a7c91 100644 --- a/pkg/vere/pier.c +++ b/pkg/vere/pier.c @@ -6,6 +6,7 @@ #include "pace.h" #include "vere.h" #include "version.h" +#include "curl/curl.h" #define PIER_READ_BATCH 1000ULL #define PIER_PLAY_BATCH 500ULL @@ -529,6 +530,181 @@ _pier_on_scry_done(void* ptr_v, u3_noun nun) u3z(nun); } +static c3_c* +_resolve_czar(u3_work* wok_u, c3_c* who_c) +{ + u3_noun czar = u3dc("scot", 'p', wok_u->pir_u->who_d[0] & ((1 << 8) - 1)); + c3_c* czar_c = u3r_string(czar); + + c3_c url[256]; + c3_w len_w; + c3_y* hun_y; + + sprintf(url, "https://%s.urbit.org/~/sponsor/%s", czar_c+1, who_c); + + c3_i ret_i = king_curl_bytes(url, &len_w, &hun_y, 1); + if (!ret_i) { + c3_free(czar_c); + czar_c = (c3_c*)hun_y; + } + + u3z(czar); + return czar_c; +} + +static c3_o +_czar_boot_data(c3_c* czar_c, + c3_c* who_c, + c3_w* bone_w, + c3_w* czar_glx_w, + c3_w* czar_ryf_w, + c3_w* czar_lyf_w, + c3_w* czar_bon_w, + c3_w* czar_ack_w) +{ + c3_c url[256]; + c3_w len_w; + c3_y* hun_y = 0; + + if ( bone_w != NULL ) { + sprintf(url, "https://%s.urbit.org/~/boot/%s/%d", + czar_c+1, who_c, *bone_w + 1); + } else { + sprintf(url, "https://%s.urbit.org/~/boot/%s", czar_c+1, who_c); + } + + c3_o ret_o = c3n; + c3_i ret_i = king_curl_bytes(url, &len_w, &hun_y, 1); + if ( !ret_i ) { + u3_noun jamd = u3i_bytes(len_w, hun_y); + u3_noun cued = u3qe_cue(jamd); + + u3_noun czar_glx, czar_ryf, czar_lyf, czar_bon, czar_ack; + + if ( (c3y == u3r_hext(cued, 0, &czar_glx, &czar_ryf, + &czar_lyf, &czar_bon, &czar_ack)) && + (c3y == u3r_safe_word(czar_glx, czar_glx_w)) && + (c3y == u3r_safe_word(czar_ryf, czar_ryf_w)) && + (c3y == u3r_safe_word(czar_lyf, czar_lyf_w)) ) { + if ( c3y == u3du(czar_bon) ) u3r_safe_word(u3t(czar_bon), czar_bon_w); + if ( c3y == u3du(czar_ack) ) u3r_safe_word(u3t(czar_ack), czar_ack_w); + ret_o = c3y; + } + + u3z(jamd); + u3z(cued); + c3_free(hun_y); + } + + return ret_o; +} + +static void +_boot_scry_cb(void* vod_p, u3_noun nun) +{ + u3_work* wok_u = (u3_work*)vod_p; + + u3_atom who = u3dc("scot", c3__p, u3i_chubs(2, wok_u->pir_u->who_d)); + c3_c* who_c = u3r_string(who); + + u3_noun rem, glx, ryf, bon, cur, nex; + c3_w glx_w, ryf_w, bon_w, cur_w, nex_w; + + c3_w czar_glx_w, czar_ryf_w, czar_lyf_w, czar_bon_w, czar_ack_w = 0xFFFFFFFF; + + if ( (c3y == u3r_qual(nun, 0, 0, 0, &rem)) && + (c3y == u3r_hext(rem, &glx, &ryf, 0, &bon, &cur, &nex)) ) { + /* + * Boot scry succeeded. Proceed to cross reference networking state against + * sponsoring galaxy. + */ + glx_w = u3r_word(0, glx); ryf_w = u3r_word(0, ryf); + bon_w = u3r_word(0, bon); cur_w = u3r_word(0, cur); + nex_w = u3r_word(0, nex); + + u3_atom czar = u3dc("scot", c3__p, glx_w); + c3_c* czar_c = u3r_string(czar); + + if ( c3n == _czar_boot_data(czar_c, who_c, &bon_w, + &czar_glx_w, &czar_ryf_w, + &czar_lyf_w, &czar_bon_w, + &czar_ack_w) ) { + u3l_log("boot: peer-state unvailable on czar, cannot protect from double-boot"); + _pier_work(wok_u); + } else { + if ( czar_ryf_w == ryf_w ) { + c3_w ack_w = cur_w - 1; + if ( czar_ack_w == 0xFFFFFFFF ) { + // This codepath should never be hit + u3l_log("boot: message-sink-state unvailable on czar, cannot protect from double-boot"); + _pier_work(wok_u); + } else if ( (czar_ack_w == ack_w) || + ((nex_w > cur_w) && (czar_ack_w - 1 == ack_w)) ) { + _pier_work(wok_u); + } else { + u3l_log("boot: failed: double-boot detected, refusing to boot %s\r\n" + "this pier is an old copy, boot the latest pier or breach\r\n" + "read more: https://docs.urbit.org/glossary/double-boot", + who_c); + u3_king_bail(); + } + } else { + // Trying to boot old ship after breach + u3l_log("boot: failed: double-boot detected, refusing to boot %s\r\n" + "this ship has been breached since its initialization, " + "boot the latest pier or breach again\r\n" + "read more: https://docs.urbit.org/glossary/double-boot", + who_c); + u3_king_bail(); + } + } + + u3z(czar); + c3_free(czar_c); + } else if ( c3y == u3r_trel(nun, 0, 0, &rem) && rem == 0 ) { + /* + * Data not available for boot scry. Check against sponsoring galaxy. + * If peer state exists exit(1) unless ship has breached, + * otherwise continue boot. + */ + c3_c* czar_c = _resolve_czar(wok_u, who_c); + + if ( c3n == _czar_boot_data(czar_c, who_c, 0, + &czar_glx_w, &czar_ryf_w, + &czar_lyf_w, 0, 0) ) { + c3_free(czar_c); + _pier_work(wok_u); + } else { + // Peer state found under czar + c3_free(czar_c); + u3_weak kf_ryf = wok_u->pir_u->ryf; + if ( kf_ryf == u3_none ) { + u3l_log("boot: keyfile rift unavailable, cannot protect from double-boot"); + _pier_work(wok_u); + } else if ( kf_ryf > czar_ryf_w ) { + // Ship has breached, continue boot + _pier_work(wok_u); + } else { + u3l_log("boot: failed: double-boot detected, refusing to boot %s\r\n" + "this ship has already been booted elsewere, " + "boot the existing pier or breach\r\n" + "read more: https://docs.urbit.org/glossary/double-boot", + who_c); + u3_king_bail(); + } + } + } else { + /* + * Boot scry endpoint doesn't exists. Most likely old arvo. + * Continue boot and hope for the best. + */ + u3l_log("boot: %%boot scry endpoint doesn't exist, cannot protect from double-boot"); + _pier_work(wok_u); + } + u3z(nun); u3z(who); + c3_free(who_c); +} + /* _pier_work_init(): begin processing new events */ static void @@ -615,7 +791,20 @@ _pier_work_init(u3_pier* pir_u) u3_auto_talk(wok_u->car_u); } - _pier_work(wok_u); + c3_d pi_d = wok_u->pir_u->who_d[0]; + c3_d pt_d = wok_u->pir_u->who_d[1]; + + if ( (pi_d < 256 && pt_d == 0) || (c3n == u3_Host.ops_u.net) ) { + // Skip double boot protection for galaxies and local mode ships + // + _pier_work(wok_u); + } else { + // Double boot protection + // + u3_noun pex = u3nc(u3i_string("boot"), u3_nul); + u3_pier_peek_last(pir_u, u3nc(u3_nul, u3_nul), c3__ax, u3_nul, pex, + pir_u->wok_u, _boot_scry_cb); + } } /* _pier_wyrd_good(): %wyrd version negotation succeeded. @@ -675,7 +864,7 @@ _pier_wyrd_fail(u3_pier* pir_u, u3_ovum* egg_u, u3_noun lud) // XX organizing version constants // #define VERE_NAME "vere" -#define VERE_ZUSE 411 +#define VERE_ZUSE 410 #define VERE_LULL 322 /* _pier_wyrd_aver(): check for %wend effect and version downgrade. RETAIN @@ -815,7 +1004,7 @@ _pier_wyrd_card(u3_pier* pir_u) u3_noun kel = u3nl(u3nc(c3__zuse, VERE_ZUSE), // XX from both king and serf? u3nc(c3__lull, VERE_LULL), // XX from both king and serf? u3nc(c3__arvo, 236), // XX from both king and serf? - u3nc(c3__hoon, 138), // god_u->hon_y + u3nc(c3__hoon, 137), // god_u->hon_y u3nc(c3__nock, 4), // god_u->noc_y u3_none); u3_noun wir = u3nc(c3__arvo, u3_nul); @@ -1609,7 +1798,7 @@ u3_pier_slog(u3_pier* pir_u) /* _pier_init(): create a pier, loading existing. */ static u3_pier* -_pier_init(c3_w wag_w, c3_c* pax_c) +_pier_init(c3_w wag_w, c3_c* pax_c, u3_weak ryf) { // create pier // @@ -1618,6 +1807,7 @@ _pier_init(c3_w wag_w, c3_c* pax_c) pir_u->pax_c = pax_c; pir_u->sat_e = u3_psat_init; pir_u->liv_o = c3n; + pir_u->ryf = ryf; // XX remove // @@ -1691,8 +1881,9 @@ u3_pier* u3_pier_stay(c3_w wag_w, u3_noun pax) { u3_pier* pir_u; + u3_weak rift = u3_none; - if ( !(pir_u = _pier_init(wag_w, u3r_string(pax))) ) { + if ( !(pir_u = _pier_init(wag_w, u3r_string(pax), rift)) ) { fprintf(stderr, "pier: stay: init fail\r\n"); u3_king_bail(); return 0; @@ -1848,7 +2039,7 @@ _pier_boot_make(u3_noun who, // include additional key configuration events if we have multiple keys // - if ( (u3_none != fed) && (c3y == u3du(u3h(fed))) ) { + if ( (u3_none != fed) && (c3y == u3du(u3h(fed))) && (u3h(u3h(fed))) == 1) { u3_noun wir = u3nt(c3__j, c3__seed, u3_nul); u3_noun tag = u3i_string("rekey"); u3_noun kyz = u3t(u3t(fed)); @@ -2027,8 +2218,13 @@ u3_pier_boot(c3_w wag_w, // config flags u3_noun mor) // extra boot sequence props { u3_pier* pir_u; + u3_weak rift = u3_none; + if (fed != u3_none && c3y == u3du(u3h(fed)) && u3h(u3h(fed)) == 2) { + rift = u3h(u3t(u3t(fed))); + u3k(rift); + } - if ( !(pir_u = _pier_init(wag_w, u3r_string(pax))) ) { + if ( !(pir_u = _pier_init(wag_w, u3r_string(pax), rift)) ) { fprintf(stderr, "pier: boot: init fail\r\n"); u3_king_bail(); return 0; diff --git a/pkg/vere/serf.c b/pkg/vere/serf.c index 78ca9708c2..a3ef017e1e 100644 --- a/pkg/vere/serf.c +++ b/pkg/vere/serf.c @@ -5,6 +5,7 @@ #include "vere.h" #include "ivory.h" #include "ur/ur.h" +#include /* |% @@ -26,12 +27,14 @@ :: next steps: [%peek mil=@ sam=*] :: gang (each path $%([%once @tas @tas path] [beam @tas beam])) [%play eve=@ lit=(list ?((pair @da ovum) *))] [%work mil=@ job=(pair @da ovum)] + [%quiz $%([%quac ~])] == :: +plea: from serf to king :: +$ plea $% [%live ~] [%ripe [pro=%1 hon=@ nok=@] eve=@ mug=@] + [%quiz $%([%quac p=*])] [%slog pri=@ tank] [%flog cord] $: %peek @@ -70,18 +73,70 @@ enum { _serf_fag_vega = 1 << 4 // kernel reset }; +/* _serf_quac: convert a quac to a noun. +*/ +u3_noun +_serf_quac(u3m_quac* mas_u) +{ + u3_noun list = u3_nul; + c3_w i_w = 0; + if ( mas_u->qua_u != NULL ) { + while ( mas_u->qua_u[i_w] != NULL ) { + list = u3nc(_serf_quac(mas_u->qua_u[i_w]), list); + i_w++; + } + } + list = u3kb_flop(list); + + u3_noun mas = u3nt(u3i_string(mas_u->nam_c), u3i_word(mas_u->siz_w), list); + + c3_free(mas_u->nam_c); + c3_free(mas_u->qua_u); + c3_free(mas_u); + + return mas; +} + +/* _serf_quacs: convert an array of quacs to a noun list. +*/ +u3_noun +_serf_quacs(u3m_quac** all_u) +{ + u3_noun list = u3_nul; + c3_w i_w = 0; + while ( all_u[i_w] != NULL ) { + list = u3nc(_serf_quac(all_u[i_w]), list); + i_w++; + } + c3_free(all_u); + return u3kb_flop(list); +} + +/* _serf_print_quacs: print an array of quacs. +*/ +void +_serf_print_quacs(FILE* fil_u, u3m_quac** all_u) +{ + fprintf(fil_u, "\r\n"); + c3_w i_w = 0; + while ( all_u[i_w] != NULL ) { + u3a_print_quac(fil_u, 0, all_u[i_w]); + i_w++; + } +} + /* _serf_grab(): garbage collect, checking for profiling. RETAIN. */ -static void -_serf_grab(u3_noun sac) +static u3_noun +_serf_grab(u3_noun sac, c3_o pri_o) { if ( u3_nul == sac) { if ( u3C.wag_w & (u3o_debug_ram | u3o_check_corrupt) ) { u3m_grab(sac, u3_none); } + return u3_nul; } else { - c3_w tot_w = 0; FILE* fil_u; #ifdef U3_MEMORY_LOG @@ -113,36 +168,77 @@ _serf_grab(u3_noun sac) #endif u3_assert( u3R == &(u3H->rod_u) ); - fprintf(fil_u, "\r\n"); - tot_w += u3a_maid(fil_u, "total userspace", u3a_prof(fil_u, 0, sac)); - tot_w += u3m_mark(fil_u); - tot_w += u3a_maid(fil_u, "space profile", u3a_mark_noun(sac)); + u3m_quac* pro_u = u3a_prof(fil_u, sac); + + if ( NULL == pro_u ) { + fflush(fil_u); + u3z(sac); + return u3_nul; + } else { + u3m_quac** all_u = c3_malloc(sizeof(*all_u) * 11); + all_u[0] = pro_u; + + u3m_quac** var_u = u3m_mark(); + all_u[1] = var_u[0]; + all_u[2] = var_u[1]; + all_u[3] = var_u[2]; + all_u[4] = var_u[3]; + c3_free(var_u); + + c3_w tot_w = all_u[0]->siz_w + all_u[1]->siz_w + all_u[2]->siz_w + + all_u[3]->siz_w + all_u[4]->siz_w; + + all_u[5] = c3_calloc(sizeof(*all_u[5])); + all_u[5]->nam_c = strdup("space profile"); + all_u[5]->siz_w = u3a_mark_noun(sac) * 4; - u3a_print_memory(fil_u, "total marked", tot_w); - u3a_print_memory(fil_u, "free lists", u3a_idle(u3R)); - u3a_print_memory(fil_u, "sweep", u3a_sweep()); + tot_w += all_u[5]->siz_w; - fflush(fil_u); + all_u[6] = c3_calloc(sizeof(*all_u[6])); + all_u[6]->nam_c = strdup("total marked"); + all_u[6]->siz_w = tot_w; + + all_u[7] = c3_calloc(sizeof(*all_u[7])); + all_u[7]->nam_c = strdup("free lists"); + all_u[7]->siz_w = u3a_idle(u3R) * 4; + + all_u[8] = c3_calloc(sizeof(*all_u[8])); + all_u[8]->nam_c = strdup("sweep"); + all_u[8]->siz_w = u3a_sweep() * 4; + + all_u[9] = c3_calloc(sizeof(*all_u[9])); + all_u[9]->nam_c = strdup("loom"); + all_u[9]->siz_w = u3C.wor_i * 4; + + all_u[10] = NULL; + + if ( c3y == pri_o ) { + _serf_print_quacs(fil_u, all_u); + } + fflush(fil_u); #ifdef U3_MEMORY_LOG - { - fclose(fil_u); - } + { + fclose(fil_u); + } #endif - u3z(sac); + u3_noun mas = _serf_quacs( all_u); + u3z(sac); - u3l_log(""); + return mas; + } } } /* u3_serf_grab(): garbage collect. */ -void -u3_serf_grab(void) +u3_noun +u3_serf_grab(c3_o pri_o) { u3_noun sac = u3_nul; + u3_noun res = u3_nul; u3_assert( u3R == &(u3H->rod_u) ); @@ -173,19 +269,31 @@ u3_serf_grab(void) u3z(gon); } - fprintf(stderr, "serf: measuring memory:\r\n"); - if ( u3_nul != sac ) { - _serf_grab(sac); + res = _serf_grab(sac, pri_o); } else { - u3a_print_memory(stderr, "total marked", u3m_mark(stderr)); + fprintf(stderr, "sac is empty\r\n"); + u3m_quac** var_u = u3m_mark(); + + c3_w tot_w = 0; + c3_w i_w = 0; + while ( var_u[i_w] != NULL ) { + tot_w += var_u[i_w]->siz_w; + u3a_quac_free(var_u[i_w]); + i_w++; + } + c3_free(var_u); + + u3a_print_memory(stderr, "total marked", tot_w / 4); u3a_print_memory(stderr, "free lists", u3a_idle(u3R)); u3a_print_memory(stderr, "sweep", u3a_sweep()); fprintf(stderr, "\r\n"); } fflush(stderr); + + return res; } /* u3_serf_post(): update serf state post-writ. @@ -213,7 +321,7 @@ u3_serf_post(u3_serf* sef_u) // XX this runs on replay too, |mass s/b elsewhere // if ( sef_u->fag_w & _serf_fag_mute ) { - _serf_grab(sef_u->sac); + u3z(_serf_grab(sef_u->sac, c3y)); sef_u->sac = u3_nul; } @@ -752,9 +860,32 @@ u3_serf_play(u3_serf* sef_u, c3_d eve_d, u3_noun lit) u3_noun u3_serf_peek(u3_serf* sef_u, c3_w mil_w, u3_noun sam) { + c3_t tac_t = !!( u3C.wag_w & u3o_trace ); + c3_c lab_c[2056]; + + // XX refactor tracing + // + if ( tac_t ) { + c3_c* foo_c = u3m_pretty(u3t(sam)); + + { + snprintf(lab_c, 2056, "peek %s", foo_c); + c3_free(foo_c); + } + + u3t_event_trace(lab_c, 'B'); + } + + u3_noun gon = u3m_soft(mil_w, u3v_peek, sam); u3_noun pro; + if ( tac_t ) { + u3t_event_trace(lab_c, 'E'); + } + + + { u3_noun tag, dat; u3x_cell(gon, &tag, &dat); @@ -906,7 +1037,7 @@ u3_serf_live(u3_serf* sef_u, u3_noun com, u3_noun* ret) } u3m_save(); - u3_serf_grab(); + u3_serf_grab(c3y); *ret = u3nc(c3__live, u3_nul); return c3y; @@ -1024,10 +1155,22 @@ u3_serf_writ(u3_serf* sef_u, u3_noun wit, u3_noun* pel) ret_o = c3y; } } break; + case c3__quiz: { + u3z(wit); + u3_noun res = u3_serf_grab(c3n); + if ( u3_none == res ) { + ret_o = c3n; + } else { + *pel = u3nt(c3__quiz, c3__quac, res); + ret_o = c3y; + } + } break; } } - u3z(wit); + if ( tag != c3__quiz ) { + u3z(wit); + } return ret_o; } @@ -1054,7 +1197,7 @@ u3_serf_init(u3_serf* sef_u) { c3_w pro_w = 1; - c3_y hon_y = 139; + c3_y hon_y = 138; c3_y noc_y = 4; u3_noun ver = u3nt(pro_w, hon_y, noc_y); diff --git a/pkg/vere/serf.h b/pkg/vere/serf.h index 7cd2ca47d0..0645434015 100644 --- a/pkg/vere/serf.h +++ b/pkg/vere/serf.h @@ -56,7 +56,8 @@ /* u3_serf_grab(): garbage collect. */ - void - u3_serf_grab(void); + u3_noun + u3_serf_grab(c3_o pri_o); + #endif /* ifndef U3_VERE_SERF_H */ diff --git a/pkg/vere/vere.h b/pkg/vere/vere.h index 71fd37fe89..2363cc02b4 100644 --- a/pkg/vere/vere.h +++ b/pkg/vere/vere.h @@ -321,6 +321,7 @@ c3_o beb; // --behn-allow-blocked c3_z siz_i; // --lmdb-map-size + c3_y jum_y; // jumbo frame size, TODO parser } u3_opts; /* u3_host: entire host. @@ -341,6 +342,8 @@ c3_o pep_o; // prep for upgrade c3_i xit_i; // exit code for shutdown void (*bot_f)(); // call when chis is up + void* sam_u; // XX + uv_udp_t wax_u; // XX } u3_host; // host == computer == process /** Pier system. @@ -457,7 +460,8 @@ u3_writ_cram = 4, u3_writ_meld = 5, u3_writ_pack = 6, - u3_writ_exit = 7 + u3_writ_exit = 7, + u3_writ_quiz = 8 } u3_writ_type; /* u3_writ: ipc message from king to serf @@ -473,6 +477,10 @@ u3_peek* pek_u; // peek u3_info fon_u; // recompute c3_d eve_d; // save/pack at + struct { // serf query: + void* ptr_v; // driver + void (*quiz_f)(void*, u3_noun); // callback + } qui_u; // }; } u3_writ; @@ -663,6 +671,7 @@ u3_disk* log_u; // event log u3_lord* god_u; // computer u3_psat sat_e; // type-tagged + u3_weak ryf; // rift union { // u3_boot* bot_u; // bootstrap u3_play* pay_u; // recompute @@ -767,7 +776,16 @@ u3_atom u3_time_t_in_ts(time_t tim); #endif + /* u3_lord_writ_new(): allocate a new writ. + */ + u3_writ* + u3_lord_writ_new(u3_lord* god_u); + /* u3_lord_writ_plan(): enqueue a writ and send. + */ + void + u3_lord_writ_plan(u3_lord* god_u, u3_writ* wit_u); + /* u3_time_out_ts(): struct timespec from urbit time. */ void @@ -1238,6 +1256,10 @@ u3_noun u3_ames_encode_lane(u3_lane); + /** mesa + **/ + u3_auto* + u3_mesa_io_init(u3_pier* pir_u); /** Autosave. **/ /* u3_save_ef_chld(): report SIGCHLD. @@ -1566,6 +1588,16 @@ darwin_register_mach_exception_handler(); #endif + /* king_curl_alloc(): allocate a response buffer for curl + */ + size_t + king_curl_alloc(void* dat_v, size_t uni_t, size_t mem_t, void* buf_v); + + /* king_curl_bytes(): HTTP GET url_c, produce response body bytes. + */ + c3_i + king_curl_bytes(c3_c* url_c, c3_w* len_w, c3_y** hun_y, c3_t veb_t); + /* u3_write_fd(): retry interrupts, continue partial writes, assert errors. */ void diff --git a/pkg/vere/xmas_tests.c b/pkg/vere/xmas_tests.c new file mode 100644 index 0000000000..58417b9c1e --- /dev/null +++ b/pkg/vere/xmas_tests.c @@ -0,0 +1,59 @@ +/// @file + +#include "./io/xmas.c" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + u3m_init(1 << 22); + u3m_pave(c3y); +} + +/* _test_ames(): spot check ames helpers +*/ +static void +_test_xmas(void) +{ + u3_lane lan_u; + lan_u.pip_w = 0x7f000001; + lan_u.por_s = 12345; + + u3_noun lan = u3_ames_encode_lane(lan_u); + u3_lane nal_u = u3_ames_decode_lane(u3k(lan)); + u3_lane nal_u2 = u3_ames_decode_lane(lan); + + if ( !(lan_u.pip_w == nal_u.pip_w && lan_u.por_s == nal_u.por_s) ) { + fprintf(stderr, "ames: lane fail (a)\r\n"); + fprintf(stderr, "pip: %d, por: %d\r\n", nal_u.pip_w, nal_u.por_s); + exit(1); + } + + + + u3_xmas_name pok_u = (u3_xmas_name) { + .her_d = {43, 0}, + .pat_c = "/foo/bar", + .pat_s = 8, + .boq_s = 13, + .fra_s = 1, + }; +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + _test_xmas(); + + // GC + // + u3m_grab(u3_none); + + fprintf(stderr, "xmas okeedokee\n"); + return 0; +}