braid-text 0.2.23 → 0.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +106 -33
- package/package.json +1 -1
- package/test/test.js +107 -2
package/index.js
CHANGED
|
@@ -800,20 +800,8 @@ function dt_len(doc, version) {
|
|
|
800
800
|
function dt_get_string(doc, version) {
|
|
801
801
|
var bytes = doc.toBytes()
|
|
802
802
|
var oplog = OpLog.fromBytes(bytes)
|
|
803
|
-
var [_agents, versions, _parentss] = dt_parse([...bytes])
|
|
804
803
|
|
|
805
|
-
var
|
|
806
|
-
|
|
807
|
-
var local_version = []
|
|
808
|
-
for (var i = 0; i < versions.length; i++) {
|
|
809
|
-
var v = versions[i].join("-")
|
|
810
|
-
if (frontier.has(v)) {
|
|
811
|
-
local_version.push(i)
|
|
812
|
-
frontier.delete(v)
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
if (frontier.size) throw new Error(`version not found: ${version}`)
|
|
804
|
+
var local_version = dt_get_local_version(bytes, version)
|
|
817
805
|
|
|
818
806
|
var b = new Branch()
|
|
819
807
|
b.merge(oplog, new Uint32Array(local_version))
|
|
@@ -1008,25 +996,25 @@ function dt_parse(byte_array) {
|
|
|
1008
996
|
|
|
1009
997
|
while (byte_array.length) {
|
|
1010
998
|
let id = byte_array.shift()
|
|
1011
|
-
let len =
|
|
999
|
+
let len = dt_read_varint(byte_array)
|
|
1012
1000
|
if (id == 1) {
|
|
1013
1001
|
} else if (id == 3) {
|
|
1014
1002
|
let goal = byte_array.length - len
|
|
1015
1003
|
while (byte_array.length > goal) {
|
|
1016
|
-
agents.push(
|
|
1004
|
+
agents.push(dt_read_string(byte_array))
|
|
1017
1005
|
}
|
|
1018
1006
|
} else if (id == 20) {
|
|
1019
1007
|
} else if (id == 21) {
|
|
1020
1008
|
let seqs = {}
|
|
1021
1009
|
let goal = byte_array.length - len
|
|
1022
1010
|
while (byte_array.length > goal) {
|
|
1023
|
-
let part0 =
|
|
1011
|
+
let part0 = dt_read_varint(byte_array)
|
|
1024
1012
|
let has_jump = part0 & 1
|
|
1025
1013
|
let agent_i = (part0 >> 1) - 1
|
|
1026
|
-
let run_length =
|
|
1014
|
+
let run_length = dt_read_varint(byte_array)
|
|
1027
1015
|
let jump = 0
|
|
1028
1016
|
if (has_jump) {
|
|
1029
|
-
let part2 =
|
|
1017
|
+
let part2 = dt_read_varint(byte_array)
|
|
1030
1018
|
jump = part2 >> 1
|
|
1031
1019
|
if (part2 & 1) jump *= -1
|
|
1032
1020
|
}
|
|
@@ -1041,12 +1029,12 @@ function dt_parse(byte_array) {
|
|
|
1041
1029
|
let count = 0
|
|
1042
1030
|
let goal = byte_array.length - len
|
|
1043
1031
|
while (byte_array.length > goal) {
|
|
1044
|
-
let run_len =
|
|
1032
|
+
let run_len = dt_read_varint(byte_array)
|
|
1045
1033
|
|
|
1046
1034
|
let parents = []
|
|
1047
1035
|
let has_more = 1
|
|
1048
1036
|
while (has_more) {
|
|
1049
|
-
let x =
|
|
1037
|
+
let x = dt_read_varint(byte_array)
|
|
1050
1038
|
let is_foreign = 0x1 & x
|
|
1051
1039
|
has_more = 0x2 & x
|
|
1052
1040
|
let num = x >> 2
|
|
@@ -1056,7 +1044,7 @@ function dt_parse(byte_array) {
|
|
|
1056
1044
|
} else if (!is_foreign) {
|
|
1057
1045
|
parents.push(versions[count - num])
|
|
1058
1046
|
} else {
|
|
1059
|
-
parents.push([agents[num - 1],
|
|
1047
|
+
parents.push([agents[num - 1], dt_read_varint(byte_array)])
|
|
1060
1048
|
}
|
|
1061
1049
|
}
|
|
1062
1050
|
parentss.push(parents)
|
|
@@ -1072,24 +1060,107 @@ function dt_parse(byte_array) {
|
|
|
1072
1060
|
}
|
|
1073
1061
|
}
|
|
1074
1062
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1063
|
+
return [agents, versions, parentss]
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
function dt_get_local_version(bytes, version) {
|
|
1067
|
+
var looking_for = new Map()
|
|
1068
|
+
for (var event of version) {
|
|
1069
|
+
var [agent, seq] = decode_version(event)
|
|
1070
|
+
if (!looking_for.has(agent)) looking_for.set(agent, [])
|
|
1071
|
+
looking_for.get(agent).push(seq)
|
|
1077
1072
|
}
|
|
1073
|
+
for (var seqs of looking_for.values())
|
|
1074
|
+
seqs.sort((a, b) => a - b)
|
|
1078
1075
|
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1076
|
+
var byte_array = [...bytes]
|
|
1077
|
+
var local_version = []
|
|
1078
|
+
var local_version_base = 0
|
|
1079
|
+
|
|
1080
|
+
if (new TextDecoder().decode(new Uint8Array(byte_array.splice(0, 8))) !== "DMNDTYPS") throw new Error("dt parse error, expected DMNDTYPS")
|
|
1081
|
+
|
|
1082
|
+
if (byte_array.shift() != 0) throw new Error("dt parse error, expected version 0")
|
|
1083
|
+
|
|
1084
|
+
let agents = []
|
|
1085
|
+
|
|
1086
|
+
while (byte_array.length && looking_for.size) {
|
|
1087
|
+
let id = byte_array.shift()
|
|
1088
|
+
let len = dt_read_varint(byte_array)
|
|
1089
|
+
if (id == 1) {
|
|
1090
|
+
} else if (id == 3) {
|
|
1091
|
+
let goal = byte_array.length - len
|
|
1092
|
+
while (byte_array.length > goal) {
|
|
1093
|
+
agents.push(dt_read_string(byte_array))
|
|
1094
|
+
}
|
|
1095
|
+
} else if (id == 20) {
|
|
1096
|
+
} else if (id == 21) {
|
|
1097
|
+
let seqs = {}
|
|
1098
|
+
let goal = byte_array.length - len
|
|
1099
|
+
while (byte_array.length > goal && looking_for.size) {
|
|
1100
|
+
let part0 = dt_read_varint(byte_array)
|
|
1101
|
+
let has_jump = part0 & 1
|
|
1102
|
+
let agent_i = (part0 >> 1) - 1
|
|
1103
|
+
let run_length = dt_read_varint(byte_array)
|
|
1104
|
+
let jump = 0
|
|
1105
|
+
if (has_jump) {
|
|
1106
|
+
let part2 = dt_read_varint(byte_array)
|
|
1107
|
+
jump = part2 >> 1
|
|
1108
|
+
if (part2 & 1) jump *= -1
|
|
1109
|
+
}
|
|
1110
|
+
let base = (seqs[agent_i] || 0) + jump
|
|
1111
|
+
|
|
1112
|
+
var agent = agents[agent_i]
|
|
1113
|
+
looking_for_seqs = looking_for.get(agent)
|
|
1114
|
+
if (looking_for_seqs) {
|
|
1115
|
+
for (var seq of splice_out_range(
|
|
1116
|
+
looking_for_seqs, base, base + run_length - 1))
|
|
1117
|
+
local_version.push(local_version_base + (seq - base))
|
|
1118
|
+
if (!looking_for_seqs.length) looking_for.delete(agent)
|
|
1119
|
+
}
|
|
1120
|
+
local_version_base += run_length
|
|
1084
1121
|
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1122
|
+
seqs[agent_i] = base + run_length
|
|
1123
|
+
}
|
|
1124
|
+
} else {
|
|
1125
|
+
byte_array.splice(0, len)
|
|
1089
1126
|
}
|
|
1090
1127
|
}
|
|
1091
1128
|
|
|
1092
|
-
|
|
1129
|
+
if (looking_for.size) throw new Error(`version not found: ${version}`)
|
|
1130
|
+
return local_version
|
|
1131
|
+
|
|
1132
|
+
function splice_out_range(a, s, e) {
|
|
1133
|
+
if (!a?.length) return [];
|
|
1134
|
+
let l = 0, r = a.length;
|
|
1135
|
+
while (l < r) {
|
|
1136
|
+
const m = Math.floor((l + r) / 2);
|
|
1137
|
+
if (a[m] < s) l = m + 1; else r = m;
|
|
1138
|
+
}
|
|
1139
|
+
const i = l;
|
|
1140
|
+
l = i; r = a.length;
|
|
1141
|
+
while (l < r) {
|
|
1142
|
+
const m = Math.floor((l + r) / 2);
|
|
1143
|
+
if (a[m] <= e) l = m + 1; else r = m;
|
|
1144
|
+
}
|
|
1145
|
+
return a.splice(i, l - i);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
function dt_read_string(byte_array) {
|
|
1150
|
+
return new TextDecoder().decode(new Uint8Array(byte_array.splice(0, dt_read_varint(byte_array))))
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
function dt_read_varint(byte_array) {
|
|
1154
|
+
let result = 0
|
|
1155
|
+
let shift = 0
|
|
1156
|
+
while (true) {
|
|
1157
|
+
if (byte_array.length === 0) throw new Error("byte array does not contain varint")
|
|
1158
|
+
|
|
1159
|
+
let byte_val = byte_array.shift()
|
|
1160
|
+
result |= (byte_val & 0x7f) << shift
|
|
1161
|
+
if ((byte_val & 0x80) == 0) return result
|
|
1162
|
+
shift += 7
|
|
1163
|
+
}
|
|
1093
1164
|
}
|
|
1094
1165
|
|
|
1095
1166
|
function dt_create_bytes(version, parents, pos, del, ins) {
|
|
@@ -1808,8 +1879,10 @@ braid_text.get_files_for_key = get_files_for_key
|
|
|
1808
1879
|
braid_text.dt_get = dt_get
|
|
1809
1880
|
braid_text.dt_get_patches = dt_get_patches
|
|
1810
1881
|
braid_text.dt_parse = dt_parse
|
|
1882
|
+
braid_text.dt_get_local_version = dt_get_local_version
|
|
1811
1883
|
braid_text.dt_create_bytes = dt_create_bytes
|
|
1812
1884
|
|
|
1813
1885
|
braid_text.decode_version = decode_version
|
|
1886
|
+
braid_text.RangeSet = RangeSet
|
|
1814
1887
|
|
|
1815
1888
|
module.exports = braid_text
|
package/package.json
CHANGED
package/test/test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
let { Doc } = require("diamond-types-node")
|
|
3
3
|
let braid_text = require('../index.js')
|
|
4
|
-
let {dt_get, dt_get_patches, dt_parse, dt_create_bytes} = braid_text
|
|
4
|
+
let {dt_get, dt_get_patches, dt_parse, dt_create_bytes, dt_get_local_version, RangeSet} = braid_text
|
|
5
5
|
|
|
6
6
|
process.on("unhandledRejection", (x) =>
|
|
7
7
|
console.log(`unhandledRejection: ${x.stack ?? x}`)
|
|
@@ -25,12 +25,117 @@ async function test_db() {
|
|
|
25
25
|
braid_text.db_folder = null
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
async function test_dt_get_local_version() {
|
|
29
|
+
for (var tt = 0; tt < 100; tt++) {
|
|
30
|
+
var st = Date.now()
|
|
31
|
+
|
|
32
|
+
var doc = new Doc('x')
|
|
33
|
+
var n = 100
|
|
34
|
+
var v_array = []
|
|
35
|
+
var p_array = []
|
|
36
|
+
var agents = ['hi']
|
|
37
|
+
var agent_rangesets = {}
|
|
38
|
+
|
|
39
|
+
for (var i = 0; i < n; i++) {
|
|
40
|
+
// console.log(`i = ${i}`)
|
|
41
|
+
|
|
42
|
+
// Math.randomSeed('seed::::' + i)
|
|
43
|
+
|
|
44
|
+
var agent = agents[0]
|
|
45
|
+
|
|
46
|
+
var seq = null
|
|
47
|
+
if (!agent_rangesets[agent]) agent_rangesets[agent] = new RangeSet()
|
|
48
|
+
var ranges = agent_rangesets[agent].ranges
|
|
49
|
+
if (!ranges.length) {
|
|
50
|
+
seq = Math.floor(Math.random() * 10)
|
|
51
|
+
} else {
|
|
52
|
+
var ii
|
|
53
|
+
if (ranges[0]?.[0] === 0)
|
|
54
|
+
ii = Math.floor(Math.random() * ranges.length)
|
|
55
|
+
else
|
|
56
|
+
ii = Math.floor(Math.random() * (ranges.length + 1)) - 1
|
|
57
|
+
var low = ii < 0 ? 0 : ranges[ii][1] + 1
|
|
58
|
+
var high = ii + 1 < ranges.length ? ranges[ii + 1][0] - 1 : ranges[ii][1] + 10
|
|
59
|
+
seq = Math.random() < 0.8 ? low : low + Math.floor(Math.random() * (high - low + 1))
|
|
60
|
+
}
|
|
61
|
+
agent_rangesets[agent].add_range(seq, seq)
|
|
62
|
+
v_array.push(`${agent}-${seq}`)
|
|
63
|
+
|
|
64
|
+
var parents = []
|
|
65
|
+
var shadow = new Set()
|
|
66
|
+
if (p_array.length) {
|
|
67
|
+
var starting_point = Math.floor(Math.random() * p_array.length)
|
|
68
|
+
parents.push(starting_point)
|
|
69
|
+
for (var p of p_array[starting_point]) shadow.add(p)
|
|
70
|
+
for (var ii = starting_point - 1; ii >= 0 && Math.random() < 0.9; ii--) {
|
|
71
|
+
if (!shadow.has(ii) && Math.random() < 0.5) {
|
|
72
|
+
parents.push(ii)
|
|
73
|
+
shadow.add(ii)
|
|
74
|
+
}
|
|
75
|
+
if (shadow.has(ii))
|
|
76
|
+
for (var p of p_array[ii])
|
|
77
|
+
shadow.add(p)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
p_array.push(parents)
|
|
81
|
+
parents = parents.map(p => v_array[p])
|
|
82
|
+
|
|
83
|
+
let args = [`${agent}-${seq}`, parents, 0, 0, 'x']
|
|
84
|
+
// console.log(args)
|
|
85
|
+
|
|
86
|
+
doc.mergeBytes(dt_create_bytes(...args))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
var bytes = doc.toBytes()
|
|
90
|
+
|
|
91
|
+
for (var t = 0; t < 100; t++) {
|
|
92
|
+
// if (t % 10 === 0) console.log(` t = ${t}`)
|
|
93
|
+
|
|
94
|
+
var version = []
|
|
95
|
+
var vv_array = [...v_array]
|
|
96
|
+
while (!version.length || (vv_array.length && Math.random() < 0.9)) {
|
|
97
|
+
version.push(vv_array.splice(Math.floor(Math.random() * vv_array.length), 1)[0])
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
var local_new = dt_get_local_version(bytes, version)
|
|
101
|
+
var local_old = old_dt_get_local_version(bytes, version)
|
|
102
|
+
|
|
103
|
+
if (local_new.some((x, i) => x != local_old[i])) {
|
|
104
|
+
throw new Error('bad!')
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
console.log(`[tt=${tt}] total T = ${Date.now() - st}`)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function old_dt_get_local_version(bytes, version) {
|
|
113
|
+
var [_agents, versions, _parentss] = dt_parse([...bytes])
|
|
114
|
+
|
|
115
|
+
var frontier = new Set(version)
|
|
116
|
+
|
|
117
|
+
var local_version = []
|
|
118
|
+
for (var i = 0; i < versions.length; i++) {
|
|
119
|
+
var v = versions[i].join("-")
|
|
120
|
+
if (frontier.has(v)) {
|
|
121
|
+
local_version.push(i)
|
|
122
|
+
frontier.delete(v)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (frontier.size) throw new Error(`version not found: ${version}`)
|
|
127
|
+
|
|
128
|
+
return local_version
|
|
129
|
+
}
|
|
130
|
+
|
|
28
131
|
async function main() {
|
|
29
132
|
let best_seed = NaN
|
|
30
133
|
let best_n = Infinity
|
|
31
134
|
let base = Math.floor(Math.random() * 10000000)
|
|
32
135
|
let st = Date.now()
|
|
33
136
|
|
|
137
|
+
await test_dt_get_local_version()
|
|
138
|
+
|
|
34
139
|
await test_db()
|
|
35
140
|
|
|
36
141
|
let og_log = console.log
|
|
@@ -38,7 +143,7 @@ async function main() {
|
|
|
38
143
|
for (let t = 0; t < 10000; t++) {
|
|
39
144
|
let seed = base + t
|
|
40
145
|
// for (let t = 0; t < 1; t++) {
|
|
41
|
-
|
|
146
|
+
// let seed = 403279
|
|
42
147
|
|
|
43
148
|
og_log(`t = ${t}, seed = ${seed}, best_n = ${best_n} @ ${best_seed}`)
|
|
44
149
|
Math.randomSeed(seed)
|