diff --git a/README.md b/README.md index 8deb2204..b4bc4d18 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,7 @@ Conditions may be compound expressions: `if (7 % 2 != 0)` and `while (i < string **Scalar:** `abs` `neg` `sign` `pow` `sqrt` `exp` `log` `min` `max` (variadic, e.g. `max(a,b,c)`) `debugger`\ **Types:** `bool` `int8` `int16` `int32` `int64` `uint8` `uint16` `uint32` `uint64` `float32` `float64` `char/utf8` `char/utf32` `char/ascii`\ **Collections:** `array` `at` `set` `has` `array.sort` `array.slice` `array.append` `dict`\ -**Shape:** `xv.numel` `xv.dim` `xv.shape` `xv.at` `xv.set`\ +**Shape:** `ndarray.numel` `ndarray.dim` `ndarray.shape` `xv.at` `xv.set`\ **KV tree:** `kv.get` `kv.set` `kv.del` `kv.deltree` `kv.list` `kv.mkindex` `kv.extindex` `kv.rmindexext` `kv.watch` `kv.has` `kv.at`\ **Strings:** `string.char` `string.ord` `string.len` `string.cmp` `string.find` `string.slice` `string.concat` `string.set`\ **Time:** `time.now` `time.sub` `time.add` `time.before` `time.after` `time/duration.nanos` `time/duration.as_nanos` (and `millis`/`seconds`/`minutes`/`hours` variants)\ @@ -223,7 +223,7 @@ Conditions may be compound expressions: `if (7 % 2 != 0)` and `while (i < string ```kv a:int64 = [7, 2, 9, 4] # typed 1D array, = ≡ <- -xv.numel(a) -> n # 4 +ndarray.numel(a) -> n # 4 at(a, 2) -> e # 9 (0-indexed) set(a, 1, 99) -> a # modify element: a becomes [7, 99, 9, 4] sort(a) -> sorted # sorted copy: [2, 4, 7, 9] diff --git a/README_CN.md b/README_CN.md index 56661404..bc9ba1ee 100644 --- a/README_CN.md +++ b/README_CN.md @@ -210,7 +210,7 @@ for (x in [7, 2, 9, 4]) { println(x) } **标量:** `abs` `neg` `sign` `pow` `sqrt` `exp` `log` `min` `max`(变参,如 `max(a,b,c)`)`debugger`\ **类型:** `bool` `int8` `int16` `int32` `int64` `uint8` `uint16` `uint32` `uint64` `float32` `float64` `char/utf8` `char/utf32` `char/ascii`\ **容器:** `array` `at` `set` `has` `array.sort` `array.slice` `array.append` `dict`\ -**形状:** `xv.numel` `xv.dim` `xv.shape` `xv.at` `xv.set`\ +**形状:** `ndarray.numel` `ndarray.dim` `ndarray.shape` `xv.at` `xv.set`\ **KV 树:** `kv.get` `kv.set` `kv.del` `kv.deltree` `kv.list` `kv.mkindex` `kv.extindex` `kv.rmindexext` `kv.watch` `kv.has` `kv.at`\ **字符串:** `string.char` `string.ord` `string.len` `string.cmp` `string.find` `string.slice` `string.concat` `string.set`\ **时间:** `time.now` `time.sub` `time.add` `time.before` `time.after` `time/duration.nanos` `time/duration.as_nanos`(及 `millis`/`seconds`/`minutes`/`hours` 变体)\ @@ -220,7 +220,7 @@ for (x in [7, 2, 9, 4]) { println(x) } ```kv a:int64 = [7, 2, 9, 4] # 带类型 1D 数组,= ≡ <- -xv.numel(a) -> n # 4 +ndarray.numel(a) -> n # 4 at(a, 2) -> e # 9 set(a, 1, 99) -> a # 修改元素:a 变为 [7, 99, 9, 4] sort(a) -> sorted # 排序副本:[2, 4, 7, 9] diff --git a/layout/build.rs b/layout/build.rs index 968600ed..1d63a1be 100644 --- a/layout/build.rs +++ b/layout/build.rs @@ -2,6 +2,16 @@ // 依赖 .so 已由 ci/deps.sh 安装到 /usr/lib;默认 kvspace-durable,KVLANG_KVSPACE_LIB=kvspace-c 时用 SHM 版。 fn main() { println!("cargo:rerun-if-env-changed=KVLANG_KVSPACE_LIB"); + let manifest = env!("CARGO_MANIFEST_DIR"); + let array2d = format!("{manifest}/../.."); // array2d 工作区 let lib = std::env::var("KVLANG_KVSPACE_LIB").unwrap_or_else(|_| "kvspace_durable".into()); + let dir = if lib == "kvspace_durable" { + format!("{array2d}/kvspace-durable/target/release") + } else { + format!("{array2d}/kvspace-c/build") + }; + println!("cargo:rustc-link-search=native={dir}"); println!("cargo:rustc-link-lib=dylib={lib}"); + println!("cargo:rustc-link-arg=-Wl,--disable-new-dtags"); + println!("cargo:rustc-link-arg=-Wl,-rpath,{dir}"); } diff --git a/layout/src/lower.rs b/layout/src/lower.rs index 4fc2ed8f..fedde228 100644 --- a/layout/src/lower.rs +++ b/layout/src/lower.rs @@ -191,7 +191,9 @@ fn lower_for_with_cont( let keys_slot = lg.tmp(); let key_slot = lg.tmp(); let is_obj = s.iter.op == "obj" - || (s.iter.is_leaf() && matches!(tm.get(&s.iter.val), Some(t) if t == "objindex")); + || s.iter.op == "map" + || (s.iter.is_leaf() + && matches!(tm.get(&s.iter.val), Some(t) if t == "objindex" || t == "[]strkeymapindex" || t == "strkeymapindex")); // 迭代源:裸标识符直接原地遍历;表达式(如数组字面量)先物化到临时槽。 let mut init_body = Vec::new(); @@ -217,15 +219,7 @@ fn lower_for_with_cont( if is_obj { init_body.push(Stmt::Instruction(Instruction { comments: Vec::new(), - expr: Some(ast::call("kv.list", vec![ast::leaf(&iter_slot)])), - writes: vec![keys_slot.clone()], - write_types: Vec::new(), - arrow_left: false, - eq: false, - })); - init_body.push(Stmt::Instruction(Instruction { - comments: Vec::new(), - expr: Some(ast::call("xv.numel", vec![ast::leaf(&keys_slot)])), + expr: Some(ast::call("kv.listlen", vec![ast::leaf(&iter_slot)])), writes: vec![len_slot.clone()], write_types: Vec::new(), arrow_left: false, @@ -234,7 +228,7 @@ fn lower_for_with_cont( } else { init_body.push(Stmt::Instruction(Instruction { comments: Vec::new(), - expr: Some(ast::call("xv.numel", vec![ast::leaf(&iter_slot)])), + expr: Some(ast::call("ndarray.numel", vec![ast::leaf(&iter_slot)])), writes: vec![len_slot.clone()], write_types: Vec::new(), arrow_left: false, @@ -271,7 +265,7 @@ fn lower_for_with_cont( if is_obj { body_insts.push(Stmt::Instruction(Instruction { comments: Vec::new(), - expr: Some(ast::call("xv.at", vec![ast::leaf(&keys_slot), ast::leaf(&idx_slot)])), + expr: Some(ast::call("kv.listn", vec![ast::leaf(&iter_slot), ast::leaf(&idx_slot)])), writes: vec![key_slot.clone()], write_types: Vec::new(), arrow_left: false, @@ -608,7 +602,7 @@ fn infer_op_type(opcode: &str, reads: &[String], tm: &mut HashMap { + "kvlen" | "ndarray.numel" | "ndarray.dim" | "kv.listlen" | "string.len" | "string.ord" | "string.cmp" | "string.find" => { return "int64".to_string(); } - "xv.shape" => return "[]int64".to_string(), + "ndarray.shape" => return "[]int64".to_string(), "kv.list" => return "[]char/utf8".to_string(), "string.char" | "string.set" | "string.slice" | "string.concat" => return "char/utf32".to_string(), "random.int63" => return "int64".to_string(), diff --git a/layout/src/parser.rs b/layout/src/parser.rs index 85557af3..b5b1a243 100644 --- a/layout/src/parser.rs +++ b/layout/src/parser.rs @@ -755,10 +755,28 @@ impl Parser { let s = inst.writes[0].clone(); let br = s.find('[').unwrap_or(s.len()); let arr = s[..br].to_string(); - let idx = s[br + 1..s.len().saturating_sub(1)].to_string(); + let idxs = s[br + 1..s.len().saturating_sub(1)].to_string(); let e = inst.expr.take(); - let op = if arr.starts_with('/') { "kv.set" } else { "xv.set" }; - inst.expr = Some(ast::call(op, vec![ast::leaf(&arr), ast::leaf(&idx), e.unwrap_or(ast::leaf(""))])); + // strkeymap 坐标写 m.[i,j] <- v:坐标段是成员名(kv.set 字符串键)。 + let dot_coord = arr.ends_with('.'); + let arr = arr.trim_end_matches('.').to_string(); + let op = if dot_coord { "kv.set" } else if arr.starts_with('/') { "kv.set" } else { "xv.set" }; + if dot_coord { + inst.expr = Some(ast::call( + op, + vec![ast::leaf(&arr), ast::str_lit(&format!("[{}]", idxs)), e.unwrap_or(ast::leaf(""))], + )); + } else { + // 多维 compact 下标:arr[i,j] <- v 展开为 xv.set(arr, i, j, v)。 + let mut args = vec![ast::leaf(&arr)]; + for idx in idxs.split(',').map(|x| x.trim()) { + if !idx.is_empty() { + args.push(ast::leaf(idx)); + } + } + args.push(e.unwrap_or(ast::leaf(""))); + inst.expr = Some(ast::call(op, args)); + } inst.writes = vec![arr]; inst.write_types = Vec::new(); } @@ -848,6 +866,26 @@ impl Parser { left = ast::call("kv.get", vec![left, ast::str_lit(&field)]); continue; } + // strkeymap 坐标访问 m.[i,j]:坐标段是单个成员名(kv.get 字符串键)。 + if self.peek().kind == Kind::LBrack { + self.advance(); + let mut idxs = Vec::new(); + while self.peek().kind != Kind::RBrack && self.peek().kind != Kind::EOF { + if self.eat(Kind::Comma) { + continue; + } + if let Some(idx) = self.parse_pratt(0) { + idxs.push(idx); + } + } + self.expect(Kind::RBrack); + let coord = format!( + "[{}]", + idxs.iter().map(|e| e.to_string()).collect::>().join(",") + ); + left = ast::call("kv.get", vec![left, ast::str_lit(&coord)]); + continue; + } } // 后缀索引 if self.peek().kind == Kind::LBrack { @@ -1328,6 +1366,24 @@ impl Parser { wtypes.push(String::new()); continue; } + if t.kind == Kind::Ident && self.peek_at(1).kind == Kind::Dot && self.peek_at(2).kind == Kind::LBrack { + let mut w = self.advance().value; // base + w.push_str(&self.advance().value); // . + w.push_str(&self.advance().value); // [ + let mut depth = 1i32; + while depth > 0 && self.peek().kind != Kind::EOF && self.peek().kind != Kind::Arrow { + if self.peek().kind == Kind::RBrack { + depth -= 1; + } + if self.peek().kind == Kind::LBrack { + depth += 1; + } + w.push_str(&self.advance().value); + } + writes.push(w); + wtypes.push(String::new()); + continue; + } let (name, typ) = self.parse_write_slot(); writes.push(name); wtypes.push(typ); diff --git a/runtime-rwirext_example/go/json/json.go b/runtime-rwirext_example/go/json/json.go index 7e5767e6..88a355b6 100644 --- a/runtime-rwirext_example/go/json/json.go +++ b/runtime-rwirext_example/go/json/json.go @@ -254,6 +254,28 @@ func constructTLV(kind string, raw []byte, arrLen int) []byte { return C.GoBytes(unsafe.Pointer(out), C.int(ol)) } +// encodeTLVDims:显式 dims/ndim 编码(供 strkeymapindex 目录标记落 dims)。 +func encodeTLVDims(kind string, raw []byte, dims []int32) []byte { + ck := cstr(kind) + defer C.free(unsafe.Pointer(ck)) + var buf unsafe.Pointer + if len(raw) > 0 { + buf = C.CBytes(raw) + defer C.free(buf) + } + carr := make([]C.int32_t, len(dims)) + for i, d := range dims { + carr[i] = C.int32_t(d) + } + var out *C.uint8_t + var ol C.uint32_t + if C.kvspaceTlvEncode(ck, (*C.uint8_t)(buf), C.uint32_t(len(raw)), &carr[0], C.int32_t(len(carr)), &out, &ol) != 0 || out == nil { + return nil + } + defer C.kvspaceBytesFree(out, ol) + return C.GoBytes(unsafe.Pointer(out), C.int(ol)) +} + // ── JSON 值 ↔ TLV ─────────────────────────────────────────────────── func readInt(raw []byte) int64 { @@ -382,6 +404,15 @@ func mkIndexMarker(kind string, names []string) []byte { return constructTLV(kind, body, 1) } +// strkeymapindex 目录标记:body 同上,dims=[len](恒一维坐标段 [i])。 +func mkMapMarker(names []string) []byte { + body := make([]byte, 4) + binary.LittleEndian.PutUint32(body, uint32(len(names))) + body = append(body, []byte(strings.Join(names, "\n"))...) + dims := []int32{int32(len(names))} + return encodeTLVDims("strkeymapindex", body, dims) +} + // validateKey:JSON 对象 key 不能含影响 kvspace 存储分隔的字符(§5.4)。 // 空串、/ . [ ] \n \r \0 U+2025 及 ASCII 控制字符一律拒绝(不静默丢键、不转义)。 func validateKey(k string) error { @@ -432,11 +463,11 @@ func writeObj(c unsafe.Pointer, path string, m map[string]any) error { func writeArr(c unsafe.Pointer, path string, arr []interface{}) error { keys := make([]string, len(arr)) for i := range arr { - keys[i] = strconv.Itoa(i) + keys[i] = fmt.Sprintf("[%d]", i) } - setTLV(c, path+".", mkIndexMarker("strkeymapindex", keys)) + setTLV(c, path+".", mkMapMarker(keys)) for i, v := range arr { - if err := writeValue(c, path+"."+strconv.Itoa(i), v); err != nil { + if err := writeValue(c, path+"."+fmt.Sprintf("[%d]", i), v); err != nil { return err } } @@ -469,14 +500,16 @@ func readObj(c unsafe.Pointer, path string) map[string]any { func readArr(c unsafe.Pointer, path string) []interface{} { idxs := make([]int, 0, 8) for _, n := range list(c, path+".") { - if i, err := strconv.Atoi(n); err == nil { + s := strings.TrimPrefix(n, "[") + s = strings.TrimSuffix(s, "]") + if i, err := strconv.Atoi(s); err == nil { idxs = append(idxs, i) } } sort.Ints(idxs) arr := make([]interface{}, len(idxs)) for i, idx := range idxs { - arr[i] = readValue(c, path+"."+strconv.Itoa(idx)) + arr[i] = readValue(c, path+"."+fmt.Sprintf("[%d]", idx)) } return arr } diff --git a/runtime-rwirext_example/go/json/tutorial/json.kv b/runtime-rwirext_example/go/json/tutorial/json.kv index 0837855f..eb557021 100644 --- a/runtime-rwirext_example/go/json/tutorial/json.kv +++ b/runtime-rwirext_example/go/json/tutorial/json.kv @@ -30,8 +30,8 @@ rwfunc main() -> () { println("c =", /data2/grp/c) println("cont =", /data2/cont) println("scat =", /data2/scat) - xv.numel(/data2/cont) -> n1 - xv.numel(/data2/scat) -> n2 + ndarray.numel(/data2/cont) -> n1 + ndarray.numel(/data2/scat) -> n2 println("len =", n1, n2) } diff --git a/runtime/src/builtin.c b/runtime/src/builtin.c index 014e413d..0eb93d57 100644 --- a/runtime/src/builtin.c +++ b/runtime/src/builtin.c @@ -5,7 +5,7 @@ typedef int (*kvlangBuiltinFn)(kvlangFrame_t *f); /* collection 模块 handler(builtin_coll.c) */ -int kvlangBuiltinArray(kvlangFrame_t *f), kvlangBuiltinXvNumel(kvlangFrame_t *f), kvlangBuiltinXvDim(kvlangFrame_t *f), kvlangBuiltinXvShape(kvlangFrame_t *f), +int kvlangBuiltinArray(kvlangFrame_t *f), kvlangBuiltinNdarrayNumel(kvlangFrame_t *f), kvlangBuiltinNdarrayDim(kvlangFrame_t *f), kvlangBuiltinNdarrayShape(kvlangFrame_t *f), kvlangBuiltinXvAt(kvlangFrame_t *f), kvlangBuiltinXvSet(kvlangFrame_t *f), kvlangBuiltinXvReshape(kvlangFrame_t *f), kvlangBuiltinScatter(kvlangFrame_t *f), kvlangBuiltinCompact(kvlangFrame_t *f), kvlangBuiltinAppend(kvlangFrame_t *f), kvlangBuiltinSlice(kvlangFrame_t *f), kvlangBuiltinObj(kvlangFrame_t *f), kvlangBuiltinMap(kvlangFrame_t *f), kvlangBuiltinStringSet(kvlangFrame_t *f), @@ -16,7 +16,7 @@ int kvlangBuiltinArray(kvlangFrame_t *f), kvlangBuiltinXvNumel(kvlangFrame_t *f) kvlangBuiltinDurArith(kvlangFrame_t *f), kvlangBuiltinDurCmp(kvlangFrame_t *f), kvlangBuiltinTimeCmp(kvlangFrame_t *f), kvlangBuiltinRandUint64(kvlangFrame_t *f), kvlangBuiltinRandInt63(kvlangFrame_t *f), kvlangBuiltinRandIntn(kvlangFrame_t *f), kvlangBuiltinKvGet(kvlangFrame_t *f), kvlangBuiltinKvSet(kvlangFrame_t *f), kvlangBuiltinKvDel(kvlangFrame_t *f), - kvlangBuiltinKvDelTree(kvlangFrame_t *f), kvlangBuiltinKvList(kvlangFrame_t *f), kvlangBuiltinKvMkindex(kvlangFrame_t *f), + kvlangBuiltinKvDelTree(kvlangFrame_t *f), kvlangBuiltinKvList(kvlangFrame_t *f), kvlangBuiltinKvListLen(kvlangFrame_t *f), kvlangBuiltinKvListN(kvlangFrame_t *f), kvlangBuiltinKvMkindex(kvlangFrame_t *f), kvlangBuiltinKvExtIndex(kvlangFrame_t *f), kvlangBuiltinKvRmIndexExt(kvlangFrame_t *f), kvlangBuiltinKvWatch(kvlangFrame_t *f), kvlangBuiltinDebugger(kvlangFrame_t *f); @@ -592,7 +592,7 @@ static const struct { const char *op; kvlangBuiltinFn fn; } builtins[] = { {"array.scatter", kvlangBuiltinScatter}, {"array.compact", kvlangBuiltinCompact}, {"array.append", kvlangBuiltinAppend}, {"array.slice", kvlangBuiltinSlice}, {"obj", kvlangBuiltinObj}, {"map", kvlangBuiltinMap}, - {"xv.numel", kvlangBuiltinXvNumel}, {"xv.dim", kvlangBuiltinXvDim}, {"xv.shape", kvlangBuiltinXvShape}, + {"ndarray.numel", kvlangBuiltinNdarrayNumel}, {"ndarray.dim", kvlangBuiltinNdarrayDim}, {"ndarray.shape", kvlangBuiltinNdarrayShape}, {"xv.at", kvlangBuiltinXvAt}, {"xv.set", kvlangBuiltinXvSet}, {"xv.reshape", kvlangBuiltinXvReshape}, {"string.set", kvlangBuiltinStringSet}, {"string.char", kvlangBuiltinStringChar}, {"string.ord", kvlangBuiltinStringOrd}, {"string.cmp", kvlangBuiltinStringCmp}, {"string.find", kvlangBuiltinStringFind}, {"string.len", kvlangBuiltinStringLen}, @@ -609,7 +609,7 @@ static const struct { const char *op; kvlangBuiltinFn fn; } builtins[] = { {"time.before", kvlangBuiltinTimeCmp}, {"time.after", kvlangBuiltinTimeCmp}, {"random.uint64", kvlangBuiltinRandUint64}, {"random.int63", kvlangBuiltinRandInt63}, {"random.intn", kvlangBuiltinRandIntn}, {"kv.get", kvlangBuiltinKvGet}, {"kv.set", kvlangBuiltinKvSet}, {"kv.del", kvlangBuiltinKvDel}, - {"kv.deltree", kvlangBuiltinKvDelTree}, {"kv.list", kvlangBuiltinKvList}, {"kv.mkindex", kvlangBuiltinKvMkindex}, + {"kv.deltree", kvlangBuiltinKvDelTree}, {"kv.list", kvlangBuiltinKvList}, {"kv.listlen", kvlangBuiltinKvListLen}, {"kv.listn", kvlangBuiltinKvListN}, {"kv.mkindex", kvlangBuiltinKvMkindex}, {"kv.extindex", kvlangBuiltinKvExtIndex}, {"kv.rmindexext", kvlangBuiltinKvRmIndexExt}, {"kv.watch", kvlangBuiltinKvWatch}, {"debugger", kvlangBuiltinDebugger}, }; @@ -777,7 +777,7 @@ static void pack_typed_array(const char *kind, const kvlangXvalue_t *elems, int static char *separated_base(kvlangKv_t *kv, const char *fp, const char *name) { char *base = kvlangBuiltinResolveWriteSlot(kv, fp, name); kvlangStrbuf_t k; kvlangStrbufInit(&k); - kvlangStrbufPuts(&k, base); kvlangStrbufPuts(&k, "[0]"); + kvlangStrbufPuts(&k, base); kvlangStrbufPuts(&k, ".[0]"); kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangKvGetOne(kv, k.p, &v); bool exists = !kvlangXvalueNone(&v); @@ -789,7 +789,7 @@ static char *separated_base(kvlangKv_t *kv, const char *fp, const char *name) { static int separated_len(kvlangKv_t *kv, const char *base) { for (int i = 0; ; i++) { kvlangStrbuf_t k; kvlangStrbufInit(&k); - kvlangStrbufPrintf(&k, "%s[%d]", base, i); + kvlangStrbufPrintf(&k, "%s.[%d]", base, i); kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangKvGetOne(kv, k.p, &v); bool none = kvlangXvalueNone(&v); @@ -798,6 +798,31 @@ static int separated_len(kvlangKv_t *kv, const char *base) { } } +/* 坐标段 key:base.[s0,s1,...]。1 维即 base.[s0]。 */ +static char *scatter_key(const char *base, const int64_t *coords, int ncoord) { + kvlangStrbuf_t b; kvlangStrbufInit(&b); + kvlangStrbufPuts(&b, base); kvlangStrbufPutc(&b, '.'); kvlangStrbufPutc(&b, '['); + for (int i = 0; i < ncoord; i++) { + if (i) kvlangStrbufPutc(&b, ','); + kvlangStrbufPrintf(&b, "%lld", (long long)coords[i]); + } + kvlangStrbufPutc(&b, ']'); + return kvlangStrbufDetach(&b); +} + +/* map 目录标记:kind=strkeymapindex,body=[4B count LE][name\n...],dims 落 head。 */ +static void map_marker(kvlangXvalue_t *out, const char *const *names, int n, const int32_t *dims, int ndim) { + kvlangStrbuf_t body; kvlangStrbufInit(&body); + char count[4] = { (char)(n & 0xFF), (char)((n >> 8) & 0xFF), (char)((n >> 16) & 0xFF), (char)((n >> 24) & 0xFF) }; + kvlangStrbufPutn(&body, count, 4); + for (int i = 0; i < n; i++) { + if (i) kvlangStrbufPutc(&body, '\n'); + kvlangStrbufPuts(&body, names[i]); + } + kvlangXvalueNewTlvDims(out, KVSPACE_KIND_MAP, (const uint8_t *)body.p, (uint32_t)body.len, dims, ndim); + kvlangStrbufFree(&body); +} + /* ── array 系列 ───────────────────────────────────────────────────── */ static void ensure_scattered(kvlangFrame_t *f, const char *base) { @@ -806,11 +831,12 @@ static void ensure_scattered(kvlangFrame_t *f, const char *base) { if (kvlangXvalueNone(&arr) || kvlangXvalueElemSize(kvlangXvalueKind(&arr)) <= 0) { kvlangXvalueFree(&arr); return; } int n = kvlangXvalueArrayLen(&arr); for (int i = 0; i < n; i++) { - kvlangStrbuf_t k; kvlangStrbufInit(&k); kvlangStrbufPrintf(&k, "%s[%d]", base, i); + int64_t c[1] = { i }; + char *k = scatter_key(base, c, 1); kvlangXvalue_t e; xvalue_at(&arr, i, &e); - kvlangKvPair_t p = { k.p, e }; + kvlangKvPair_t p = { k, e }; char err[256]; kvlangKvSet(f->kv, &p, 1, err, sizeof err); - kvlangXvalueFree(&e); kvlangStrbufFree(&k); + kvlangXvalueFree(&e); free(k); } kvlangXvalueFree(&arr); char err[256]; kvlangKvDel(f->kv, base, err, sizeof err); @@ -834,29 +860,19 @@ int kvlangBuiltinArray(kvlangFrame_t *f) { return 0; } -int kvlangBuiltinXvNumel(kvlangFrame_t *f) { +int kvlangBuiltinNdarrayNumel(kvlangFrame_t *f) { kvlangXvalue_t in[1]; int n = read_inputs(f, in, 1); int64_t n_el = 0; - if (n > 0 && kvlangXvalueNone(&in[0]) && f->inst->nr > 0) { - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *base = separated_base(f->kv, fr, f->inst->reads[0].name); - if (base) { n_el = separated_len(f->kv, base); free(base); } - free(fr); - } else if (n > 0) n_el = kvlangXvalueArrayLen(&in[0]); + if (n > 0) n_el = kvlangXvalueArrayLen(&in[0]); kvlangXvalue_t r; kvlangXvalueNewInt64(&r, n_el); int rc = write_result(f, &r); kvlangXvalueFree(&r); free_inputs(in, n); return rc; } -int kvlangBuiltinXvDim(kvlangFrame_t *f) { +int kvlangBuiltinNdarrayDim(kvlangFrame_t *f) { kvlangXvalue_t in[1]; int n = read_inputs(f, in, 1); int64_t ndim = 0; - if (n > 0 && kvlangXvalueNone(&in[0]) && f->inst->nr > 0) { - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *base = separated_base(f->kv, fr, f->inst->reads[0].name); - if (base) { ndim = 1; free(base); } - free(fr); - } else if (n > 0) { + if (n > 0) { kvspaceHead_t h; kvlangXvalueHead(&in[0], &h); kvlang_kindexpr_t kx; kvlang_kindexpr_parse(h.kindexpr, &kx); ndim = kx.ndim; @@ -866,15 +882,10 @@ int kvlangBuiltinXvDim(kvlangFrame_t *f) { return rc; } -int kvlangBuiltinXvShape(kvlangFrame_t *f) { +int kvlangBuiltinNdarrayShape(kvlangFrame_t *f) { kvlangXvalue_t in[1]; int n = read_inputs(f, in, 1); int32_t dims[8]; int32_t ndim = 0; - if (n > 0 && kvlangXvalueNone(&in[0]) && f->inst->nr > 0) { - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *base = separated_base(f->kv, fr, f->inst->reads[0].name); - if (base) { dims[0] = separated_len(f->kv, base); ndim = 1; free(base); } - free(fr); - } else if (n > 0 && !kvlangXvalueNone(&in[0])) { + if (n > 0 && !kvlangXvalueNone(&in[0])) { kvspaceHead_t h; kvlangXvalueHead(&in[0], &h); kvlang_kindexpr_t kx; kvlang_kindexpr_parse(h.kindexpr, &kx); ndim = kx.ndim; @@ -907,19 +918,6 @@ int kvlangBuiltinXvAt(kvlangFrame_t *f) { int nidx = f->inst->nr - 1; if (nidx < 1) return set_err(f, "TypeError: xv.at requires array and indices"); kvlangXvalue_t in[MAX_PARAMS]; int n = read_inputs(f, in, MAX_PARAMS); - /* 散 key 数组(kv.list 产出的 key 列表):base[idx] 平方括号寻址 */ - if (nidx == 1 && kvlangXvalueNone(&in[0]) && f->inst->nr > 0) { - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *base = separated_base(f->kv, fr, f->inst->reads[0].name); - if (base) { - int idx = (int)kvlangXvalueAsInt64(&in[1]); - kvlangStrbuf_t k; kvlangStrbufInit(&k); kvlangStrbufPrintf(&k, "%s[%d]", base, idx); - kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangKvGetOne(f->kv, k.p, &v); - int rc = write_result(f, &v); kvlangXvalueFree(&v); kvlangStrbufFree(&k); - free(base); free(fr); free_inputs(in, n); return rc; - } - free(fr); - } const char *k = kvlangXvalueKind(&in[0]); int sz = kvlangXvalueElemSize(k); kvspaceHead_t h; kvspaceDecodeHead(in[0].data, in[0].len, &h); @@ -994,11 +992,25 @@ int kvlangBuiltinScatter(kvlangFrame_t *f) { char *fr = kvlangKeytreeFrameRoot(f->pc); char *dst = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); int al = kvlangXvalueArrayLen(&in[0]); + if (al > 0) { + char **names = malloc(sizeof(char *) * (size_t)al); + for (int i = 0; i < al; i++) { + kvlangStrbuf_t s; kvlangStrbufInit(&s); kvlangStrbufPrintf(&s, "[%d]", i); + names[i] = kvlangStrbufDetach(&s); + } + int32_t dims[1] = { al }; + kvlangXvalue_t mark; map_marker(&mark, (const char *const *)names, al, dims, 1); + kvlangKvPair_t p0 = { dst, mark }; char err[256]; kvlangKvSet(f->kv, &p0, 1, err, sizeof err); + kvlangXvalueFree(&mark); + for (int i = 0; i < al; i++) free(names[i]); + free(names); + } for (int i = 0; i < al; i++) { - kvlangStrbuf_t k; kvlangStrbufInit(&k); kvlangStrbufPrintf(&k, "%s[%d]", dst, i); + int64_t c[1] = { i }; + char *k = scatter_key(dst, c, 1); kvlangXvalue_t e; xvalue_at(&in[0], i, &e); - kvlangKvPair_t p = { k.p, e }; char err[256]; kvlangKvSet(f->kv, &p, 1, err, sizeof err); - kvlangXvalueFree(&e); kvlangStrbufFree(&k); + kvlangKvPair_t p = { k, e }; char err[256]; kvlangKvSet(f->kv, &p, 1, err, sizeof err); + kvlangXvalueFree(&e); free(k); } free(dst); free(fr); next_pc(f); free_inputs(in, n); return 0; @@ -1010,9 +1022,10 @@ int kvlangBuiltinCompact(kvlangFrame_t *f) { char *src = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->reads[0].name); kvlangXvalue_t elems[1024]; int n = 0; for (int i = 0; ; i++) { - kvlangStrbuf_t k; kvlangStrbufInit(&k); kvlangStrbufPrintf(&k, "%s[%d]", src, i); - kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangKvGetOne(f->kv, k.p, &v); - bool none = kvlangXvalueNone(&v); kvlangStrbufFree(&k); + int64_t c[1] = { i }; + char *k = scatter_key(src, c, 1); + kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangKvGetOne(f->kv, k, &v); + bool none = kvlangXvalueNone(&v); free(k); if (none) break; elems[n++] = v; } @@ -1034,10 +1047,11 @@ int kvlangBuiltinAppend(kvlangFrame_t *f) { char *base = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); ensure_scattered(f, base); int len = separated_len(f->kv, base); - kvlangStrbuf_t k; kvlangStrbufInit(&k); kvlangStrbufPrintf(&k, "%s[%d]", base, len); - kvlangKvPair_t p = { k.p, n >= 2 ? in[1] : in[0] }; + int64_t c[1] = { len }; + char *k = scatter_key(base, c, 1); + kvlangKvPair_t p = { k, n >= 2 ? in[1] : in[0] }; char err[256]; kvlangKvSet(f->kv, &p, 1, err, sizeof err); - kvlangStrbufFree(&k); free(base); free(fr); + free(k); free(base); free(fr); next_pc(f); free_inputs(in, n); return 0; } @@ -1052,15 +1066,17 @@ int kvlangBuiltinSlice(kvlangFrame_t *f) { int lo = (int)kvlangXvalueAsInt64(&in[1]), hi = (int)kvlangXvalueAsInt64(&in[2]); if (lo < 0 || hi < lo || hi > al) { free(base); free(fr); free_inputs(in, n); return set_err(f, "IndexError: array.slice: bounds [%d:%d] out of range (len=%d)", lo, hi, al); } for (int i = lo; i < hi; i++) { - kvlangStrbuf_t sk; kvlangStrbufInit(&sk); kvlangStrbufPrintf(&sk, "%s[%d]", base, i); - kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangKvGetOne(f->kv, sk.p, &v); - kvlangStrbuf_t dk; kvlangStrbufInit(&dk); kvlangStrbufPrintf(&dk, "%s[%d]", base, i - lo); - kvlangKvPair_t p = { dk.p, v }; char err[256]; kvlangKvSet(f->kv, &p, 1, err, sizeof err); - kvlangXvalueFree(&v); kvlangStrbufFree(&sk); kvlangStrbufFree(&dk); + int64_t sc[1] = { i }, dc[1] = { i - lo }; + char *sk = scatter_key(base, sc, 1); + kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangKvGetOne(f->kv, sk, &v); + char *dk = scatter_key(base, dc, 1); + kvlangKvPair_t p = { dk, v }; char err[256]; kvlangKvSet(f->kv, &p, 1, err, sizeof err); + kvlangXvalueFree(&v); free(sk); free(dk); } for (int i = hi - lo; i < al; i++) { - kvlangStrbuf_t dk; kvlangStrbufInit(&dk); kvlangStrbufPrintf(&dk, "%s[%d]", base, i); - char err[256]; kvlangKvDel(f->kv, dk.p, err, sizeof err); kvlangStrbufFree(&dk); + int64_t dc[1] = { i }; + char *dk = scatter_key(base, dc, 1); + char err[256]; kvlangKvDel(f->kv, dk, err, sizeof err); free(dk); } free(base); free(fr); next_pc(f); free_inputs(in, n); return 0; @@ -1096,20 +1112,35 @@ int kvlangBuiltinMap(kvlangFrame_t *f) { char *fr = kvlangKeytreeFrameRoot(f->pc); for (int w = 0; w < f->inst->nw; w++) { char *ok = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[w].name); - /* 散 key 数组:base[i] 方括号下标,无根标记(对齐 array.scatter/separated_len)。 */ + /* 散 key 数组:元素在 ok.[i],目录标记(kind=strkeymapindex,dims=[n])在 ok。 */ int old = separated_len(f->kv, ok); for (int i = 0; i < old; i++) { - kvlangStrbuf_t k; kvlangStrbufInit(&k); kvlangStrbufPrintf(&k, "%s[%d]", ok, i); - char err[256]; kvlangKvDel(f->kv, k.p, err, sizeof err); kvlangStrbufFree(&k); + int64_t c[1] = { i }; + char *k = scatter_key(ok, c, 1); + char err[256]; kvlangKvDel(f->kv, k, err, sizeof err); free(k); } char err[256]; kvlangKvDel(f->kv, ok, err, sizeof err); + + char **names = malloc(sizeof(char *) * (size_t)(n > 0 ? n : 1)); + int64_t *cs = malloc(sizeof(int64_t) * (size_t)(n > 0 ? n : 1)); + for (int i = 0; i < n; i++) { + kvlangStrbuf_t s; kvlangStrbufInit(&s); kvlangStrbufPrintf(&s, "[%d]", i); + names[i] = kvlangStrbufDetach(&s); cs[i] = i; + } + int32_t dims[1] = { n }; + if (n > 0) { + kvlangXvalue_t mark; map_marker(&mark, (const char *const *)names, n, dims, 1); + kvlangKvPair_t p0 = { ok, mark }; + kvlangKvSet(f->kv, &p0, 1, err, sizeof err); + kvlangXvalueFree(&mark); + } for (int i = 0; i < n; i++) { - kvlangStrbuf_t k; kvlangStrbufInit(&k); kvlangStrbufPrintf(&k, "%s[%d]", ok, i); - kvlangKvPair_t p = { k.p, in[i] }; + char *k = scatter_key(ok, &cs[i], 1); + kvlangKvPair_t p = { k, in[i] }; kvlangKvSet(f->kv, &p, 1, err, sizeof err); - kvlangStrbufFree(&k); + free(k); free(names[i]); } - free(ok); + free(names); free(cs); free(ok); } free(fr); next_pc(f); free_inputs(in, n); return 0; @@ -1435,23 +1466,93 @@ int kvlangBuiltinKvList(kvlangFrame_t *f) { char *fr = kvlangKeytreeFrameRoot(f->pc); char *dst = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); free(fr); + /* 结果是一个 strkeymapindex:目录标记在 dst(dims=[count]),成员名是坐标段 [i], + * 值是对应的成员名字符串。 */ + if (count > 0) { + char **coords = malloc(sizeof(char *) * (size_t)count); + for (int i = 0; i < count; i++) { + kvlangStrbuf_t s; kvlangStrbufInit(&s); kvlangStrbufPrintf(&s, "[%d]", i); + coords[i] = kvlangStrbufDetach(&s); + } + int32_t dims[1] = { count }; + kvlangXvalue_t mark; map_marker(&mark, (const char *const *)coords, count, dims, 1); + kvlangKvPair_t p0 = { dst, mark }; char err[256]; kvlangKvSet(f->kv, &p0, 1, err, sizeof err); + kvlangXvalueFree(&mark); + for (int i = 0; i < count; i++) free(coords[i]); + free(coords); + } for (int i = 0; i < count; i++) { - kvlangStrbuf_t k; kvlangStrbufInit(&k); kvlangStrbufPrintf(&k, "%s[%d]", dst, i); + int64_t c[1] = { i }; + char *k = scatter_key(dst, c, 1); kvlangXvalue_t e; kvlangXvalueNewCharUtf8(&e, names[i]); - kvlangKvPair_t p = { k.p, e }; char err[256]; kvlangKvSet(f->kv, &p, 1, err, sizeof err); - kvlangXvalueFree(&e); kvlangStrbufFree(&k); free(names[i]); + kvlangKvPair_t p = { k, e }; char err[256]; kvlangKvSet(f->kv, &p, 1, err, sizeof err); + kvlangXvalueFree(&e); free(k); free(names[i]); } for (int i = count; ; i++) { - kvlangStrbuf_t k; kvlangStrbufInit(&k); kvlangStrbufPrintf(&k, "%s[%d]", dst, i); - kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangKvGetOne(f->kv, k.p, &v); + int64_t c[1] = { i }; + char *k = scatter_key(dst, c, 1); + kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangKvGetOne(f->kv, k, &v); bool none = kvlangXvalueNone(&v); kvlangXvalueFree(&v); - if (none) { kvlangStrbufFree(&k); break; } - char err[256]; kvlangKvDel(f->kv, k.p, err, sizeof err); kvlangStrbufFree(&k); + if (none) { free(k); break; } + char err[256]; kvlangKvDel(f->kv, k, err, sizeof err); free(k); } free(names); free(dst); free(key); next_pc(f); free_inputs(in, n); return 0; } +/* 解析 obj/map 成员目录 key(/.),供 kv.list/listlen/listn 共用。 */ +static char *kv_list_dir(kvlangFrame_t *f, kvlangXvalue_t *in, int n) { + char *key = n >= 1 ? path_arg(f, 0, in) : NULL; + if (!key && f->inst->nr >= 1) { + const char *name = f->inst->reads[0].name; + if (name[0] != '/') { + char *fr = kvlangKeytreeFrameRoot(f->pc); + char *ff = kvlangBuiltinFuncFrameRoot(f->kv, fr); + char *base = kvlangBuiltinResolveWriteSlot(f->kv, ff, name); + free(ff); free(fr); + key = kvlangKeytreeMember(base, ""); + free(base); + } + } + return key; +} + +int kvlangBuiltinKvListLen(kvlangFrame_t *f) { + kvlangXvalue_t in[1]; int n = read_inputs(f, in, 1); + char *key = kv_list_dir(f, in, n); + int64_t count = 0; + if (key) { + char **names = NULL; int cnt = 0; + kvlangKvList(f->kv, key, false, false, &names, &cnt); + for (int i = 0; i < cnt; i++) free(names[i]); + free(names); + count = cnt; + free(key); + } + kvlangXvalue_t r; kvlangXvalueNewInt64(&r, count); + int rc = write_result(f, &r); kvlangXvalueFree(&r); free_inputs(in, n); + return rc; +} + +int kvlangBuiltinKvListN(kvlangFrame_t *f) { + kvlangXvalue_t in[2]; int n = read_inputs(f, in, 2); + char *key = kv_list_dir(f, in, n); + int idx = n >= 2 ? (int)kvlangXvalueAsInt64(&in[1]) : -1; + kvlangXvalue_t r; kvlangXvalueZero(&r); + if (key && idx >= 0) { + char **names = NULL; int cnt = 0; + kvlangKvList(f->kv, key, false, false, &names, &cnt); + if (idx < cnt) { + kvlangXvalueNewCharUtf8(&r, names[idx]); + } + for (int i = 0; i < cnt; i++) free(names[i]); + free(names); + free(key); + } + int rc = write_result(f, &r); kvlangXvalueFree(&r); free_inputs(in, n); + return rc; +} + int kvlangBuiltinKvMkindex(kvlangFrame_t *f) { return kv_path_void(f, "kv.mkindex", kvlangKvMkindex); } int kvlangBuiltinKvExtIndex(kvlangFrame_t *f) { diff --git a/tutorial/01-basics/kv_tree.kv b/tutorial/01-basics/kv_tree.kv index 8b1ae268..83c05673 100644 --- a/tutorial/01-basics/kv_tree.kv +++ b/tutorial/01-basics/kv_tree.kv @@ -17,12 +17,12 @@ rwfunc main() -> () { kv.set("/tmp/kvt/a", 1) kv.set("/tmp/kvt/b", 2) kv.list("/tmp/kvt/") -> names - xv.numel(names) -> n + ndarray.numel(names) -> n println("n=", n) - xv.numel([10,20,30]) -> m - xv.dim([10,20,30]) -> d + ndarray.numel([10,20,30]) -> m + ndarray.dim([10,20,30]) -> d println("numel=", m, "dim=", d) - xv.shape([10,20,30]) -> s + ndarray.shape([10,20,30]) -> s println("shape0=", s[0]) } main() diff --git a/tutorial/02-func/accumulator.kv b/tutorial/02-func/accumulator.kv index 7410a3fd..9d460752 100644 --- a/tutorial/02-func/accumulator.kv +++ b/tutorial/02-func/accumulator.kv @@ -7,7 +7,7 @@ # 10 # 10 rwfunc sum(arr:[]int64) -> (acc:int64) { - n = xv.numel(arr) # = 等价于 <- + n = ndarray.numel(arr) # = 等价于 <- 0 -> acc # 显式初始化累加器(strict null:write parm 首读为 null,拒绝 null 算术) 0 -> i while (i < n) { @@ -17,7 +17,7 @@ rwfunc sum(arr:[]int64) -> (acc:int64) { } rwfunc rsum(arr:[]int64, i:int64, acc:int64) -> (r:int64) { - n <- xv.numel(arr) + n <- ndarray.numel(arr) if (i >= n) { acc -> r diff --git a/tutorial/04-ndarray/continuous.kv b/tutorial/04-ndarray/continuous.kv index 0e6a2d50..d6f01753 100644 --- a/tutorial/04-ndarray/continuous.kv +++ b/tutorial/04-ndarray/continuous.kv @@ -7,7 +7,7 @@ # sum = 179 rwfunc main() -> () { a:[]int64 = [10, 20, 30, 40] - xv.numel(a) -> n + ndarray.numel(a) -> n println("len =", n) v0 <- a[0] println("[0] =", v0) diff --git a/tutorial/04-ndarray/map_coord.kv b/tutorial/04-ndarray/map_coord.kv new file mode 100644 index 00000000..09fa3816 --- /dev/null +++ b/tutorial/04-ndarray/map_coord.kv @@ -0,0 +1,13 @@ +# strkeymap_coord: strkeymapindex 坐标段访问 a.[i] +# 语义: {..} 创建 1 维散 key map,成员名是坐标段 "[i]",a.[i] 走 kv.get +# 期望输出: +# a[0] = 10 +# a[2] = 30 +rwfunc main() -> () { + a = {10, 20, 30} + a.[0] -> v0 + a.[2] -> v2 + println("a[0] =", v0) + println("a[2] =", v2) +} +main() diff --git a/tutorial/04-ndarray/separated.kv b/tutorial/04-ndarray/separated.kv index cf649fa4..b8c27c2a 100644 --- a/tutorial/04-ndarray/separated.kv +++ b/tutorial/04-ndarray/separated.kv @@ -1,22 +1,22 @@ -# separated: 散 key 数组(元素分散在 b[0]..b[N-1] 各自 key,按 key 寻址) +# separated: 散 key 数组(元素分散在 b.[0]..b.[N-1] 各自 key,按坐标段寻址) # 语义: 字面量初始化默认 compact;array.scatter 把 compact 转散 key,array.compact 反向 -# 散 key 元素访问与 compact 一致,统一用 [i] +# 散 key 元素访问用 b.[i](走 kv.get),compact 用 b[i](走 xv.at) # 期望输出: -# xv.numel(b) = 3 +# ndarray.numel(b) = 3 # b[0] = 10 # b[2] = 30 -# xv.numel(c) = 3 +# ndarray.numel(c) = 3 # c[0] = 10 rwfunc main() -> () { a:[]int64 = [10, 20, 30] # 字面量初始化 → compact - b <- array.scatter(a) # 显式 scatter:compact a → 散 key b(b[0]..b[2]) - xv.numel(b) -> n1 - println("xv.numel(b) =", n1) - println("b[0] =", b[0]) # 散 key 元素访问 [i] - println("b[2] =", b[2]) + b <- array.scatter(a) # 显式 scatter:compact a → 散 key b(b.[0]..b.[2]) + ndarray.numel(b) -> n1 + println("ndarray.numel(b) =", n1) + println("b[0] =", b.[0]) # 散 key 元素访问 .[i] + println("b[2] =", b.[2]) c <- array.compact(b) # 显式 compact:散 key b → compact c - xv.numel(c) -> n2 - println("xv.numel(c) =", n2) + ndarray.numel(c) -> n2 + println("ndarray.numel(c) =", n2) println("c[0] =", c[0]) # compact 元素访问 [i] } diff --git a/tutorial/04-ndarray/xv_shape.kv b/tutorial/04-ndarray/xv_shape.kv index c5dd188b..14b0167d 100644 --- a/tutorial/04-ndarray/xv_shape.kv +++ b/tutorial/04-ndarray/xv_shape.kv @@ -5,10 +5,10 @@ # set1= 99 rwfunc main() -> () { a:[]int64 = [10, 20, 30, 40] - xv.numel(a) -> n - xv.dim(a) -> d + ndarray.numel(a) -> n + ndarray.dim(a) -> d println("numel=", n, "dim=", d) - xv.shape(a) -> s + ndarray.shape(a) -> s println("shape0=", s[0]) xv.at(a, 1) -> e println("at1=", e) diff --git a/tutorial/08-leetcode/001_two-sum-hash.kv b/tutorial/08-leetcode/001_two-sum-hash.kv index 6775d4ef..6f6c6d7d 100644 --- a/tutorial/08-leetcode/001_two-sum-hash.kv +++ b/tutorial/08-leetcode/001_two-sum-hash.kv @@ -3,7 +3,7 @@ # 期望输出: # [ 0 , 1 ] rwfunc two_sum(nums:[]int64, target:int64) -> () { - n <- xv.numel(nums) + n <- ndarray.numel(nums) i = 0 # = 等价于 <- "/tmp" -> h while (i < n) { diff --git a/tutorial/08-leetcode/001_two_sum.kv b/tutorial/08-leetcode/001_two_sum.kv index b9b29ed2..be9d267d 100644 --- a/tutorial/08-leetcode/001_two_sum.kv +++ b/tutorial/08-leetcode/001_two_sum.kv @@ -4,7 +4,7 @@ # [ 0 , 1 ] # [-1, -1] rwfunc two_sum(nums:[]int64, target:int64) -> () { - n <- xv.numel(nums) + n <- ndarray.numel(nums) found = 0 # = 等价于 <- 0 -> i while (i < n) { diff --git a/tutorial/08-leetcode/011_container_water.kv b/tutorial/08-leetcode/011_container_water.kv index 505d6fe8..94901be3 100644 --- a/tutorial/08-leetcode/011_container_water.kv +++ b/tutorial/08-leetcode/011_container_water.kv @@ -3,7 +3,7 @@ # 期望输出: # 49 rwfunc max_area(h:[]int64) -> (mx:int64) { - xv.numel(h) -> n + ndarray.numel(h) -> n l <- 0 r = n - 1 # = 等价于 <- 0 -> mx diff --git a/tutorial/08-leetcode/026_remove_dupes.kv b/tutorial/08-leetcode/026_remove_dupes.kv index a8442582..d6f60e0b 100644 --- a/tutorial/08-leetcode/026_remove_dupes.kv +++ b/tutorial/08-leetcode/026_remove_dupes.kv @@ -5,7 +5,7 @@ # k = 5 rwfunc remove_dupes() -> (k:int64) { a:[]int64 = [0, 0, 1, 1, 1, 2, 2, 3, 3, 4] - xv.numel(a) -> n + ndarray.numel(a) -> n k <- 1 i = 1 # = 等价于 <- while (i < n) { diff --git a/tutorial/08-leetcode/027_remove_element.kv b/tutorial/08-leetcode/027_remove_element.kv index f17d9b24..ef96ddfa 100644 --- a/tutorial/08-leetcode/027_remove_element.kv +++ b/tutorial/08-leetcode/027_remove_element.kv @@ -9,7 +9,7 @@ rwfunc remove_element() -> () { a:[]int64 = [3, 2, 2, 3] # = 等价于 <- 3 -> val - n <- xv.numel(a) + n <- ndarray.numel(a) k = 0 # = 等价于 <- 0 -> i while (i < n) { diff --git a/tutorial/08-leetcode/033_search_rotated.kv b/tutorial/08-leetcode/033_search_rotated.kv index e61df8e0..bf1d851f 100644 --- a/tutorial/08-leetcode/033_search_rotated.kv +++ b/tutorial/08-leetcode/033_search_rotated.kv @@ -5,7 +5,7 @@ # 4 rwfunc search() -> () { a:[]int64 <- [4, 5, 6, 7, 0, 1, 2] - n = xv.numel(a) # = 等价于 <- + n = ndarray.numel(a) # = 等价于 <- 0 -> target lo <- 0 hi = n - 1 # = 等价于 <- diff --git a/tutorial/08-leetcode/034_search_range.kv b/tutorial/08-leetcode/034_search_range.kv index c5a7b838..20524142 100644 --- a/tutorial/08-leetcode/034_search_range.kv +++ b/tutorial/08-leetcode/034_search_range.kv @@ -5,7 +5,7 @@ # [ 3 , 4 ] rwfunc search_range() -> () { [5, 7, 7, 8, 8, 10] -> a:[]int64 - n <- xv.numel(a) + n <- ndarray.numel(a) target = 8 # = 等价于 <- # find left 0 -> lo diff --git a/tutorial/08-leetcode/035_search_insert.kv b/tutorial/08-leetcode/035_search_insert.kv index 8c3e0276..ed9b410a 100644 --- a/tutorial/08-leetcode/035_search_insert.kv +++ b/tutorial/08-leetcode/035_search_insert.kv @@ -6,7 +6,7 @@ rwfunc search_insert() -> () { a:[]int64 = [1, 3, 5, 6] # = 等价于 <- 5 -> target - n <- xv.numel(a) + n <- ndarray.numel(a) lo = 0 # = 等价于 <- n - 1 -> hi pos <- 0 diff --git a/tutorial/08-leetcode/053_max_subarray.kv b/tutorial/08-leetcode/053_max_subarray.kv index 3baf6c07..b4ece722 100644 --- a/tutorial/08-leetcode/053_max_subarray.kv +++ b/tutorial/08-leetcode/053_max_subarray.kv @@ -5,7 +5,7 @@ # 6 rwfunc max_subarray(nums:[]int64) -> () { a:[]int64 <- [-2, 1, -3, 4, -1, 2, 1, -5, 4] - n = xv.numel(a) # = 等价于 <- + n = ndarray.numel(a) # = 等价于 <- a[0] -> cur max <- a[0] i = 1 # = 等价于 <- diff --git a/tutorial/08-leetcode/055_jump_game.kv b/tutorial/08-leetcode/055_jump_game.kv index 24caf55d..4764cc0c 100644 --- a/tutorial/08-leetcode/055_jump_game.kv +++ b/tutorial/08-leetcode/055_jump_game.kv @@ -5,7 +5,7 @@ # false rwfunc can_jump(nums:[]int64) -> (ok:int64) { ok = 1 # = 等价于 <- - n <- xv.numel(nums) + n <- ndarray.numel(nums) 0 -> reach i = 0 # = 等价于 <- while (i < n) { diff --git a/tutorial/08-leetcode/066_plus_one.kv b/tutorial/08-leetcode/066_plus_one.kv index 2ed222ca..7474fdcc 100644 --- a/tutorial/08-leetcode/066_plus_one.kv +++ b/tutorial/08-leetcode/066_plus_one.kv @@ -10,7 +10,7 @@ # 0 rwfunc plus_one() -> () { a:[]int64 <- [1, 2, 3] - n = xv.numel(a) # = 等价于 <- + n = ndarray.numel(a) # = 等价于 <- n - 1 -> i carry <- 1 while (i >= 0) { @@ -41,7 +41,7 @@ rwfunc plus_one() -> () { rwfunc plus_one_nines() -> () { a:[]int64 = [9, 9, 9] # = 等价于 <- - xv.numel(a) -> n + ndarray.numel(a) -> n i <- n - 1 carry = 1 # = 等价于 <- while (i >= 0) { diff --git a/tutorial/08-leetcode/075_sort_colors.kv b/tutorial/08-leetcode/075_sort_colors.kv index 2ffe24a6..be699b6b 100644 --- a/tutorial/08-leetcode/075_sort_colors.kv +++ b/tutorial/08-leetcode/075_sort_colors.kv @@ -9,7 +9,7 @@ # 2 rwfunc sort_colors() -> () { nums:[]int64 = [2, 0, 2, 1, 1, 0] - n = xv.numel(nums) # = 等价于 <- + n = ndarray.numel(nums) # = 等价于 <- lo = 0 # = 等价于 <- mid <- 0 hi = n - 1 # = 等价于 <- diff --git a/tutorial/08-leetcode/121_buy_sell_stock.kv b/tutorial/08-leetcode/121_buy_sell_stock.kv index 409d5cd5..18957529 100644 --- a/tutorial/08-leetcode/121_buy_sell_stock.kv +++ b/tutorial/08-leetcode/121_buy_sell_stock.kv @@ -5,7 +5,7 @@ # 5 rwfunc max_profit() -> () { a:[]int64 = [7, 1, 5, 3, 6, 4] # = 等价于 <- - xv.numel(a) -> n + ndarray.numel(a) -> n min_price <- a[0] max_profit = 0 # = 等价于 <- 1 -> i diff --git a/tutorial/08-leetcode/125_valid_palindrome.kv b/tutorial/08-leetcode/125_valid_palindrome.kv index 29a8f4c9..fd7a1c7b 100644 --- a/tutorial/08-leetcode/125_valid_palindrome.kv +++ b/tutorial/08-leetcode/125_valid_palindrome.kv @@ -6,7 +6,7 @@ # 用整数数组模拟字符串,1='a', 2='b', etc. rwfunc is_pal() -> () { s:[]int64 = [1, 2, 1] # = 等价于 <- - xv.numel(s) -> n + ndarray.numel(s) -> n l <- 0 r = n - 1 # = 等价于 <- 1 -> ok @@ -28,7 +28,7 @@ rwfunc is_pal() -> () { rwfunc not_pal() -> () { s:[]int64 = [1, 2] # = 等价于 <- - xv.numel(s) -> n + ndarray.numel(s) -> n l <- 0 r = n - 1 # = 等价于 <- 1 -> ok diff --git a/tutorial/08-leetcode/136_single_number.kv b/tutorial/08-leetcode/136_single_number.kv index 5be514ec..3e69dafe 100644 --- a/tutorial/08-leetcode/136_single_number.kv +++ b/tutorial/08-leetcode/136_single_number.kv @@ -5,7 +5,7 @@ # 4 rwfunc single_number() -> () { a:[]int64 <- [4, 1, 2, 1, 2] - n = xv.numel(a) # = 等价于 <- + n = ndarray.numel(a) # = 等价于 <- a[0] -> result i <- 1 while (i < n) { diff --git a/tutorial/08-leetcode/153_find_min_rotated.kv b/tutorial/08-leetcode/153_find_min_rotated.kv index 9a97d570..74b09698 100644 --- a/tutorial/08-leetcode/153_find_min_rotated.kv +++ b/tutorial/08-leetcode/153_find_min_rotated.kv @@ -4,7 +4,7 @@ # 0 rwfunc find_min() -> () { a:[]int64 <- [4, 5, 6, 7, 0, 1, 2] - n = xv.numel(a) # = 等价于 <- + n = ndarray.numel(a) # = 等价于 <- 0 -> lo hi <- n - 1 while (lo < hi) { diff --git a/tutorial/08-leetcode/162_find_peak.kv b/tutorial/08-leetcode/162_find_peak.kv index e1b204fe..f2c9d8b5 100644 --- a/tutorial/08-leetcode/162_find_peak.kv +++ b/tutorial/08-leetcode/162_find_peak.kv @@ -4,7 +4,7 @@ # 2 rwfunc find_peak() -> () { a:[]int64 <- [1, 2, 3, 1] - n = xv.numel(a) # = 等价于 <- + n = ndarray.numel(a) # = 等价于 <- 0 -> lo hi <- n - 1 while (lo < hi) { diff --git a/tutorial/08-leetcode/167_two_sum_ii.kv b/tutorial/08-leetcode/167_two_sum_ii.kv index 6dbce946..242ad87a 100644 --- a/tutorial/08-leetcode/167_two_sum_ii.kv +++ b/tutorial/08-leetcode/167_two_sum_ii.kv @@ -5,7 +5,7 @@ rwfunc two_sum_ii() -> () { [2, 7, 11, 15] -> a:[]int64 target <- 9 - n = xv.numel(a) # = 等价于 <- + n = ndarray.numel(a) # = 等价于 <- 0 -> l r <- n - 1 while (l < r) { diff --git a/tutorial/08-leetcode/169_majority.kv b/tutorial/08-leetcode/169_majority.kv index 4b9880b1..f261da73 100644 --- a/tutorial/08-leetcode/169_majority.kv +++ b/tutorial/08-leetcode/169_majority.kv @@ -5,7 +5,7 @@ # 3 rwfunc majority() -> () { a:[]int64 = [3, 2, 3] # = 等价于 <- - xv.numel(a) -> n + ndarray.numel(a) -> n candidate <- a[0] count = 1 # = 等价于 <- 1 -> i diff --git a/tutorial/08-leetcode/189_rotate_array.kv b/tutorial/08-leetcode/189_rotate_array.kv index 324bb372..c7b9bf61 100644 --- a/tutorial/08-leetcode/189_rotate_array.kv +++ b/tutorial/08-leetcode/189_rotate_array.kv @@ -25,7 +25,7 @@ rwfunc swap(a_len:int64, lo:int64, hi:int64) -> () { rwfunc rotate() -> () { a:[]int64 <- [1, 2, 3, 4, 5, 6, 7] - n = xv.numel(a) # = 等价于 <- + n = ndarray.numel(a) # = 等价于 <- 3 -> k k_eff <- k % n # reverse all diff --git a/tutorial/08-leetcode/198_house_robber.kv b/tutorial/08-leetcode/198_house_robber.kv index 15ecf9e7..98a5b358 100644 --- a/tutorial/08-leetcode/198_house_robber.kv +++ b/tutorial/08-leetcode/198_house_robber.kv @@ -4,7 +4,7 @@ # 4 rwfunc rob() -> () { [1, 2, 3, 1] -> a:[]int64 - n <- xv.numel(a) + n <- ndarray.numel(a) one = n == 1 # = 等价于 <- n == 2 -> two diff --git a/tutorial/08-leetcode/217_contains_dup.kv b/tutorial/08-leetcode/217_contains_dup.kv index 9f823ec8..72fbded1 100644 --- a/tutorial/08-leetcode/217_contains_dup.kv +++ b/tutorial/08-leetcode/217_contains_dup.kv @@ -6,7 +6,7 @@ # false rwfunc has_dup() -> () { a:[]int64 = [1, 2, 3, 1] # = 等价于 <- - xv.numel(a) -> n + ndarray.numel(a) -> n found <- false i = 0 # = 等价于 <- while (i < n) { @@ -37,7 +37,7 @@ rwfunc has_dup() -> () { rwfunc no_dup() -> () { a:[]int64 <- [1, 2, 3, 4] - n = xv.numel(a) # = 等价于 <- + n = ndarray.numel(a) # = 等价于 <- false -> found i <- 0 while (i < n) { diff --git a/tutorial/08-leetcode/217_contains_dup_hash.kv b/tutorial/08-leetcode/217_contains_dup_hash.kv index 6cdc9a93..05e0204f 100644 --- a/tutorial/08-leetcode/217_contains_dup_hash.kv +++ b/tutorial/08-leetcode/217_contains_dup_hash.kv @@ -4,7 +4,7 @@ # true # false rwfunc has_dup(a:[]int64) -> () { - xv.numel(a) -> n + ndarray.numel(a) -> n seen = {} # = 等价于 <- found <- false i = 0 # = 等价于 <- @@ -31,7 +31,7 @@ rwfunc has_dup(a:[]int64) -> () { rwfunc no_dup() -> () { a:[]int64 = [1, 2, 3, 4] # = 等价于 <- - xv.numel(a) -> n + ndarray.numel(a) -> n seen = {} # = 等价于 <- found <- false i = 0 # = 等价于 <- diff --git a/tutorial/08-leetcode/219_contains_dup_ii.kv b/tutorial/08-leetcode/219_contains_dup_ii.kv index 198b374c..cd77c3cf 100644 --- a/tutorial/08-leetcode/219_contains_dup_ii.kv +++ b/tutorial/08-leetcode/219_contains_dup_ii.kv @@ -4,7 +4,7 @@ # true # false rwfunc near_dup(nums:[]int64, k:int64) -> () { - n <- xv.numel(nums) + n <- ndarray.numel(nums) h = {} # = 等价于 <- found = false # = 等价于 <- 0 -> i diff --git a/tutorial/08-leetcode/238_product_except_self.kv b/tutorial/08-leetcode/238_product_except_self.kv index c37ce072..4f474fe7 100644 --- a/tutorial/08-leetcode/238_product_except_self.kv +++ b/tutorial/08-leetcode/238_product_except_self.kv @@ -8,7 +8,7 @@ # 6 rwfunc product() -> () { a:[]int64 = [1, 2, 3, 4] # = 等价于 <- - xv.numel(a) -> n + ndarray.numel(a) -> n prefix <- 1 suffix = 1 # = 等价于 <- # build prefix products into result diff --git a/tutorial/08-leetcode/268_missing_number.kv b/tutorial/08-leetcode/268_missing_number.kv index 0295403c..b18e5dc7 100644 --- a/tutorial/08-leetcode/268_missing_number.kv +++ b/tutorial/08-leetcode/268_missing_number.kv @@ -5,7 +5,7 @@ # 2 rwfunc missing() -> () { a:[]int64 <- [3, 0, 1] - n = xv.numel(a) # = 等价于 <- + n = ndarray.numel(a) # = 等价于 <- 0 -> s i <- 0 while (i < n) { diff --git a/tutorial/08-leetcode/283_move_zeroes.kv b/tutorial/08-leetcode/283_move_zeroes.kv index 4d5cfdcb..696a0492 100644 --- a/tutorial/08-leetcode/283_move_zeroes.kv +++ b/tutorial/08-leetcode/283_move_zeroes.kv @@ -8,7 +8,7 @@ # 0 rwfunc move_zeroes() -> () { a:[]int64 = [0, 1, 0, 3, 12] # = 等价于 <- - n <- xv.numel(a) + n <- ndarray.numel(a) 0 -> w 0 -> i while (i < n) { diff --git a/tutorial/08-leetcode/303_range_sum.kv b/tutorial/08-leetcode/303_range_sum.kv index bc0a4a3e..43c43db1 100644 --- a/tutorial/08-leetcode/303_range_sum.kv +++ b/tutorial/08-leetcode/303_range_sum.kv @@ -5,7 +5,7 @@ # -1 rwfunc range_sum() -> () { a:[]int64 <- [-2, 0, 3, -5, 2, -1] - n = xv.numel(a) # = 等价于 <- + n = ndarray.numel(a) # = 等价于 <- # build prefix sums [0, 0, 0, 0, 0, 0] -> p:[]int64 s <- a[0] diff --git a/tutorial/08-leetcode/344_reverse_string.kv b/tutorial/08-leetcode/344_reverse_string.kv index deb3b4f4..60c43898 100644 --- a/tutorial/08-leetcode/344_reverse_string.kv +++ b/tutorial/08-leetcode/344_reverse_string.kv @@ -9,7 +9,7 @@ rwfunc reverse_str() -> () { # char 值数组: "hello" → ASCII [104, 101, 108, 108, 111] a:[]int64 = [104, 101, 108, 108, 111] - n <- xv.numel(a) + n <- ndarray.numel(a) l = 0 # = 等价于 <- n - 1 -> r while (l < r) { diff --git a/tutorial/08-leetcode/349_intersection.kv b/tutorial/08-leetcode/349_intersection.kv index 0e9a814b..9137fa04 100644 --- a/tutorial/08-leetcode/349_intersection.kv +++ b/tutorial/08-leetcode/349_intersection.kv @@ -4,9 +4,9 @@ # 2 rwfunc intersection() -> () { a:[]int64 = [1, 2, 2, 1] # = 等价于 <- - xv.numel(a) -> na + ndarray.numel(a) -> na b:[]int64 <- [2, 2] - nb = xv.numel(b) # = 等价于 <- + nb = ndarray.numel(b) # = 等价于 <- [0, 0] -> r:[]int64 idx <- 0 count = 0 # = 等价于 <- diff --git a/tutorial/08-leetcode/414_third_max.kv b/tutorial/08-leetcode/414_third_max.kv index 73502a04..0bfa9bd1 100644 --- a/tutorial/08-leetcode/414_third_max.kv +++ b/tutorial/08-leetcode/414_third_max.kv @@ -4,7 +4,7 @@ # 1 rwfunc third_max() -> () { a:[]int64 = [2, 2, 3, 1] # = 等价于 <- - xv.numel(a) -> n + ndarray.numel(a) -> n # track top 3 first <- 0 second = 0 # = 等价于 <-