@orieg/expanse

中文文档
0.17.0发布于 2026/11/02MIT OR Apache-2.0TypeScriptCommonJS零依赖构建来源已验证

Clean-room,纯rust现代Judy数组和数字尝试,具有缓存线调优的节点几何,内联值打包,slab竞技场以及node .js, Bun和Deno的OCC并发性。

中文使用文档
文档目录11 节
  1. 概述
  2. 安装
  3. 快速入门
  4. 64位整数集( ExpanseSet )
  5. 64位整型映射( ExpanseMap )
  6. 前缀压缩字符串映射( ExpanseStrMap )
  7. 任意二值图( ExpanseBytesMap )
  8. 高性能Blob Map ( ExpanseBlobMap )
  9. 并发结构( SyncExpanseMap / SyncExpanseSet )
  10. 并发字符串、字节、有序字节和blob映射
  11. 许可证

@orieg /片(expanse-node)

本地Node.js, Bun和Deno绑定 广阔的:洁净室,纯rust Judy数组和256字节的数字尝试,具有乐观并发控制(OCC)。

npm version License

概述

@orieg/expanse 为JavaScript和TypeScript运行时提供插入式、零依赖、超快速的稀疏数据结构:

  • ExpanseSet: 64位无符号整数集(compat: Judy1),具有排名/选择和范围查询。
  • ExpanseMap: 64位整型键值映射(compat: JudyL)。
  • ExpanseStrMap:使用前缀压缩的字节字典排序字符串映射(compat: JudySL)。
  • ExpanseBytesMap:任意二进制键的无序映射(包括 \0 字节)(compat: JudyHS)。
  • ExpanseBlobMap:多态blob存储与内联值打包(≤7字节内联存储与0堆分配),块slab竞技场,就地压缩,和mmap图像持久性。
  • SyncExpanseMap / SyncExpanseSet具有乐观并发控制(OCC)和基于时代的内存回收的线程安全并发结构。
  • SyncExpanseStrMap / SyncExpanseBytesMap / SyncExpanseOrderedBytesMap / SyncExpanseBlobMap:字符串、字节串、有序字节串和blob(字节负载加上24位热元数据)映射具有相同的并发形式。

安装

npm install @orieg/expanse
# or
bun add @orieg/expanse
# or
pnpm add @orieg/expanse

快速入门

64位整数集(ExpanseSet)

import { ExpanseSet } from '@orieg/expanse';

const set = new ExpanseSet();
set.add(42n);
set.add(100n);
set.add(500n);

console.log(set.has(42n)); // true
console.log(set.size());   // 3n

// Rank / Select
console.log(set.rank(100n)); // 1n (1 element strictly < 100)
console.log(set.select(0n));  // 42n (0-th element)

// Navigation
console.log(set.next(42n));  // 100n
console.log(set.prev(500n)); // 100n

// Range queries
console.log(set.countRange(40n, 200n)); // 2n
console.log(set.range(40n, 200n));      // [42n, 100n]

64位整型映射(ExpanseMap)

import { ExpanseMap } from '@orieg/expanse';

const map = new ExpanseMap();
map.set(100n, 9999n);
map.set(200n, 8888n);

console.log(map.get(100n)); // 9999n
console.log(map.first());   // { key: 100n, value: 9999n }

前缀压缩字符串映射(ExpanseStrMap)

import { ExpanseStrMap } from '@orieg/expanse';

const strmap = new ExpanseStrMap();
strmap.set('apple', 1n);
strmap.set('banana', 2n);
strmap.set('cherry', 3n);

console.log(strmap.get('banana')); // 2n
console.log(strmap.first());        // { key: 'apple', value: 1n }
console.log(strmap.next('apple'));  // { key: 'banana', value: 2n }

任意二值图(ExpanseBytesMap)

import { ExpanseBytesMap } from '@orieg/expanse';

const bytesmap = new ExpanseBytesMap();
const binaryKey = Buffer.from([0x00, 0x01, 0x02, 0xff]);
bytesmap.set(binaryKey, 42n);

console.log(bytesmap.get(binaryKey)); // 42n

高性能Blob Map (ExpanseBlobMap)

import { ExpanseBlobMap } from '@orieg/expanse';

const blobmap = new ExpanseBlobMap();

// Short payloads (<= 7 bytes) written with hot metadata 0 are stored inline in the
// value slot (0 heap allocations); with metadata they are arena records that keep it
blobmap.set(1n, Buffer.from('inline'), 0);

// Larger payloads are allocated in contiguous slab arenas
blobmap.set(2n, Buffer.from('large payload allocated in slab arena'), 20);

// Lookup with metadata
const res = blobmap.getWithMeta(1n);
console.log(res);
// { payload: <Buffer 69 6e 6c 69 6e 65>, hotMeta: 10, isInline: true }

// Prune based on hot metadata
blobmap.prune((key, hotMeta) => hotMeta > 15);

// Relocatable binary image persistence
blobmap.saveImage('./data.expanse');
const reloaded = ExpanseBlobMap.openImage('./data.expanse');

并发结构(SyncExpanseMap / SyncExpanseSet)

import { SyncExpanseMap, SyncExpanseSet } from '@orieg/expanse';

const syncMap = new SyncExpanseMap();
syncMap.set(1000n, 42n);
console.log(syncMap.get(1000n)); // 42n
console.log(syncMap.next(1000n, true)); // { key: 1000n, value: 42n }

SyncExpanseMap的 get, has, size, first, last, next 和 prev 运行在 乐观路径:除非读耗尽了它的边界,否则它们不使用写锁 重试,在这种情况下,返回到排除写入器的路径。协议是 阻塞乐观锁耦合,而不是无锁。 rank, select, countRange, keys, values 和 entries的有序读取 SyncExpanseSetrun with:跑 作家排除在外。

SyncExpanseMap 还具有原子读-修改-写功能(#1194)。 compareExchange(key, expected, newValue) 商店 newValue 仅当键的当前值为 expected, null 意思是双方都缺席((null, v) 缺席时插入; (e, null) 移除if =),并返回 { stored, observed }: observed 是比较所看到的值(null 如果不存在),则失败的调用将返回要重试的值。 getOrInsert(key, value) 商店 value 仅当键不存在并返回现有值时,或 null 的约定 set)。 update(key, fn) 商店 fn(current) (null 移除键)并返回被替换的值;这是一个循环 compareExchange 调用 fn 当交换损失时,再次使用观察值,因此 fn 每次调用可以运行多次,并且必须没有副作用,以及来自 fn 在键不变的情况下传播。插件的对象属于一个JavaScript线程,因此交换只会在读取和交换之间进行写操作时丢失(例如从内部) fn)。

syncMap.update(7n, (cur) => (cur ?? 0n) + 1n); // atomic increment
syncMap.compareExchange(7n, 1n, null); // { stored: true, observed: 1n }: remove if equal to 1n

并发字符串、字节、有序字节和blob映射

import {
  SyncExpanseStrMap,
  SyncExpanseBytesMap,
  SyncExpanseOrderedBytesMap,
  SyncExpanseBlobMap,
} from '@orieg/expanse';

const names = new SyncExpanseStrMap(); // NUL-free string keys, u64 values
names.set('alice', 1n);
names.update('alice', (cur) => (cur ?? 0n) + 1n); // atomic increment
names.next('alice'); // { key: ..., value: ... } | null, byte-lexicographical order

const raw = new SyncExpanseBytesMap(); // Buffer / Uint8Array / string keys, any bytes
raw.compareExchange(Buffer.from([0, 1]), null, 5n); // { stored: true, observed: null }

const ordered = new SyncExpanseOrderedBytesMap();
ordered.first(); // { key: Buffer, value: bigint } | null

const blobs = new SyncExpanseBlobMap();
blobs.set(1n, Buffer.alloc(64, 1), 5 /* hotMeta */);
blobs.get(1n); // Buffer
blobs.compareExchangeMeta(1n, 5, 6); // { stored: true, observed: 5 }
blobs.getOrInsert(2n, 'payload longer than seven bytes'); // null: stored

四种都是一样的 compareExchange(key, expected, newValue) 和 getOrInsert 形式 SyncExpanseMap (null 缺席; { stored, observed }), update(key, fn) 在三上 word-valued地图。字符串映射拒绝带有嵌入式NUL的键。 get, has,重点 写入和字符串映射 first / last / next / prev 在乐观的道路上奔跑;这个 ordered-bytes地图的 first / last / next / prev 运行与作家排除在外,所以每个调用 阻塞并发写器。Blob读取返回owned Buffer秒; getWithMeta 增加了 isInline, 任何长度的有效负载都保留了编写时使用的热元数据(#1548)。blob compareExchange, compareExchangeMeta 和 getOrInsert 当map拒绝该值时抛出(元数据超过24位, (拒绝竞技场),其中C形式返回状态。就像 SyncExpanseMap,对象属于 一个JavaScript线程,因此交换只损失在两者之间进行的写操作(例如在内部) fn)。

许可证

在MIT和Apache-2.0下双重授权。

版本与发布记录

@orieg/expanse 共发布 24 个版本,首次发布于 2026/08/24;过去 12 个月发布了 24 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.17.0latest2026/11/021 天前
0.16.02026/10/268 天前
0.15.02026/10/2014 天前
0.14.02026/10/1816 天前
0.13.02026/10/1519 天前
0.12.02026/10/1321 天前

关于 @orieg/expanse 的常见问题

@orieg/expanse 是什么?

Clean-room,纯rust现代Judy数组和数字尝试,具有缓存线调优的节点几何,内联值打包,slab竞技场以及node .js, Bun和Deno的OCC并发性。

如何安装 @orieg/expanse?

在项目目录运行 npm install @orieg/expanse,或使用 pnpm add / yarn add / bun add。

@orieg/expanse 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@orieg/expanse 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@orieg/expanse 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >= 20.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@orieg/expanse 可以商用吗?

@orieg/expanse 使用 MIT OR Apache-2.0 许可。可在 MIT、Apache-2.0 中任选其一遵守。选择 MIT 时,宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@orieg/expanse 还在维护吗?

最新版本 0.17.0 发布于 2026/11/02(1 天前);至今共发布 24 个版本,其中过去 12 个月发布了 24 个;首次发布于 2026/08/24。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。